FTP客户端 - FTP服务器中的文件/文件夹列表无效

时间:2009-07-10 09:11:28

标签: c# ftp

我正在使用C#开发自己的FTP客户端,并且 - 有什么好奇的 - 有时(它开始经常更多)我从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 个答案:

答案 0 :(得分:4)

好吧,有一件事,你大多忽略了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;
    }
}

另请注意,您每次都是从NetStrm创建一个新的StreamReader。这可能是一个坏主意 - 我会创建一个StreamReader和一个StreamWriter都包装NetStrm,然后你根本不需要处理二进制数据。否则,新的StreamReader可能会读取比您要求的行更多的数据,导致您下次错过数据。