FTP-клиент - неверный список файлов / папок с FTP-сервера - PullRequest
0 голосов
/ 10 июля 2009

Я разрабатываю свой собственный FTP-клиент на C #, и - что любопытно - иногда (это начиналось чаще) я получаю список недействительных (поврежденных) файлов / папок с FTP-сервера, это выглядит так: *

drwxr--r--   1 user     group          0 Jul 10 08:53 .\r
drwxr--r--   1 user     group          0 Jun 19 10:47 NetBeansProjects\r
drwxr--r--   1 user     group          0 May 28 22:07 NFS Most Wanted\r
0 May 28 18:57 My Skype Content\r
drwxr--r--   1 user     group      drwxr-

Что любопытно - иногда приведенный выше список верен:

drwxr--r--   1 user     group          0 Jul 10 08:53 .\r
drwxr--r--   1 user     group          0 Jun 19 10:47 NetBeansProjects\r
drwxr--r--   1 user     group          0 May 28 22:07 NFS Most Wanted\r
drwxr--r--   1 user     group          0 May 28 18:57 My Skype Content\r

Метод, который получает список файлов / папок с FTP-сервера: (Я также прикрепил другие методы, которые связаны с этим методом getRemoteFolders ())

    public void getRemoteFolders()
    {
        string fileOrFolder;
        string folderList="";

        folderList = Encoding.ASCII.GetString(sendPassiveFTPcmd("LIST\r\n"));
        filesAndFolders = folderList.Split("\n".ToCharArray());

        [...] //the rest of the code, not important
    }

    public byte[] sendPassiveFTPcmd(string cmd)
    {
        byte[] szData;
        System.Collections.ArrayList al = new ArrayList();
        byte[] RecvBytes = new byte[Byte.MaxValue];
        Int32 bytes;
        Int32 totalLength = 0;
        szData = System.Text.Encoding.ASCII.GetBytes(cmd.ToCharArray());

        NetworkStream passiveConnection;
        passiveConnection = createPassiveConnection();

        tbStatus.Text += "\r\nSent:" + cmd;
        StreamReader commandStream = new StreamReader(NetStrm);
        NetStrm.Write(szData, 0, szData.Length);
        while (true)
        {
            bytes = passiveConnection.Read(RecvBytes, 0, RecvBytes.Length);
            if (bytes <= 0) break;
            totalLength += bytes;
            al.AddRange(RecvBytes);
        }
        al = al.GetRange(0, totalLength);
        tbStatus.Text += "\r\nRcvd:" + commandStream.ReadLine(); // 125
        tbStatus.Text += "\r\nRcvd:" + commandStream.ReadLine(); // 226
        return (byte[])al.ToArray((new byte()).GetType());
    }

    private NetworkStream createPassiveConnection()
    {
        string[] commaSeperatedValues;
        int highByte = 0;
        int lowByte = 0;
        int passivePort = 0;
        string response = "";
        response = sendFTPcmd("PASV\r\n");

        commaSeperatedValues = response.Split(",".ToCharArray());
        highByte = Convert.ToInt16(commaSeperatedValues[4]) * 256;
        commaSeperatedValues[5] =
        commaSeperatedValues[5].Substring(0,
        commaSeperatedValues[5].IndexOf(")"));
        lowByte = Convert.ToInt16(commaSeperatedValues[5]);
        passivePort = lowByte + highByte;
        TcpClient clientSocket = new TcpClient(server, passivePort);
        NetworkStream pasvStrm = clientSocket.GetStream();
        return pasvStrm;
    }

    public string sendFTPcmd(string cmd)
    {
        byte[] szData;
        string returnedData = "";
        StreamReader RdStrm = new StreamReader(NetStrm);
        szData = Encoding.ASCII.GetBytes(cmd.ToCharArray());
        NetStrm.Write(szData, 0, szData.Length);
        tbStatus.Text += "\r\nSent:" + cmd;
        returnedData = RdStrm.ReadLine();
        tbStatus.Text += "\r\nRcvd:" + returnedData;
        return returnedData;
    }

Кто-нибудь знает, в чем проблема?

1 Ответ

4 голосов
/ 10 июля 2009

Ну, во-первых, вы в основном игнорируете значение, возвращаемое Read - вы звоните al.AddRange(RecvBytes), как если бы оно было заполнено действительными данными - чего вполне может не быть.

Существует гораздо более простой способ чтения байтового массива из потока - используйте MemoryStream. Например:

public static byte[] ReadFully(Stream input)
{
    byte[] buffer = new byte[16*1024];
    using (MemoryStream ms = new MemoryStream())
    {
        int read;
        while ((read = input.Read(buffer, 0, buffer.Length)) > 0)
        {
            ms.Write(buffer, 0, read);
        }
        return ms.ToArray();
    }
}

(Кстати, вы используете .NET 1.1? Если так, то действительно стоит избегать неуниверсальных коллекций ...)

Я заметил, что вы также не закрываете поток - плохая идея. Используйте оператор using, чтобы закрыть поток, например, так (имена изменились, чтобы быть более .NET идиоматическими тоже):

public byte[] SendPassiveFTPcmd(string cmd)
{
    using (Stream passiveConnection = CreatePassiveConnections())
    {
        byte[] commandData = Encoding.ASCII.GetBytes(cmd);
        NetStrm.Write(commandData, 0, commandData.Length);
        tbStatus.Text += "\r\nSent:" + cmd;

        byte[] data = ReadFully(passiveConnection);

        StreamReader commandStream = new StreamReader(NetStrm);
        tbStatus.Text += "\r\nRcvd:" + commandStream.ReadLine(); // 125
        tbStatus.Text += "\r\nRcvd:" + commandStream.ReadLine(); // 226
        return data;
    }
}

Также обратите внимание, что вы каждый раз создаете новый StreamReader из NetStrm. Вероятно, это плохая идея - я бы создал один StreamReader и один StreamWriter, оба обертывающие NetStrm, и тогда вам вообще не нужно иметь дело с двоичными данными. В противном случае новые StreamReaders могут считывать больше данных, чем запрашиваемые вами строки, в результате чего в следующий раз вы пропустите данные.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...