2009-07-10 76 views
0

我正在使用C#開發我自己的FTP客戶端,以及 - 有些什麼好奇的 - 有時候(它開始經常出現)我收到無效的(損壞的)文件/從FTP服務器上,它看起來就像是: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服務器接收的文件/文件夾列表的方法是: (我還附加了與我相關的其他方法的ThOD 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; 
    } 

不要任何人都知道問題出在哪裏?

回答

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; 
    } 
} 

另外請注意,您要創建一個新的StreamReader從NetStrm各一次。這可能是一個壞主意 - 我會創建一個StreamReader和一個StreamWriter來包裝NetStrm,然後根本不需要處理二進制數據。否則,新的StreamReader可能會讀取更多的數據,而不僅僅是您要求的行,導致您下次錯過數據。