我正在使用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;
}
有谁知道问题出在哪里?
答案 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可能会读取比您要求的行更多的数据,导致您下次错过数据。