2013-04-09 82 views
1

我想要使用StreamReader來獲取樹視圖上的文件,目錄和子目錄的完整列表。問題是花了太長時間,拋出*「操作超時異常」,只顯示一個級別。使用C#列出服務器文件夾和子文件夾FtpWebRequest

這裏是我的代碼

public void getServerSubfolder(TreeNode tv, string parentNode) { 
    string ptNode; 
    List<string> files = new List<string>(); 
    try { 
    FtpWebRequest request = (FtpWebRequest) WebRequest. 
    Create(parentNode); 
    request.Method = WebRequestMethods.Ftp.ListDirectoryDetails; 

    request.Credentials = new NetworkCredential(this.userName, this.Password); 
    request.UseBinary = true; 
    request.UsePassive = true; 
    request.Timeout = 10000; 
    request.ReadWriteTimeout = 10000; 
    request.KeepAlive = false; 
    FtpWebResponse response = (FtpWebResponse) request.GetResponse(); 
    Stream responseStream = response.GetResponseStream(); 
    StreamReader reader = new StreamReader(responseStream); 
    string fileList; 
    string[] fileName; 
    //MessageBox.Show(reader.ReadToEnd().ToString()); 
    while (!reader.EndOfStream) { 
     fileList = reader.ReadLine(); 
     fileName = fileList.Split(' '); 
     if (fileName[0] == "drwxr-xr-x") { 
     // if it is directory 
     TreeNode tnS = new TreeNode(fileName[fileName.Length - 1]); 
     tv.Nodes.Add(tnS); 
     ptNode = parentNode + "/" + fileName[fileName.Length - 1] + "/"; 
     getServerSubfolder(tnS, ptNode); 
     } else files.Add(fileName[fileName.Length - 1]); 
    } 
    reader.Close(); 
    response.Close(); 
    } catch (Exception ex) { 
    MessageBox.Show("Sub--here " + ex.Message + "----" + ex.StackTrace); 
    } 
} 
+0

我有不同的超時數字嘗試過。 – Habtamu 2013-04-09 14:43:40

回答

1

我在做類似的事情,但不是使用StreamReader.ReadLine()爲每一個,我StreamReader.ReadToEnd得到這一切在一次()。你不需要ReadLine()來獲取目錄列表。下面是我的整個代碼(整個HOWTO在this教程解釋):

 FtpWebRequest request=(FtpWebRequest)FtpWebRequest.Create(path); 
     request.Method=WebRequestMethods.Ftp.ListDirectoryDetails; 
     List<ftpinfo> files=new List<ftpinfo>(); 

     //request.Proxy = System.Net.WebProxy.GetDefaultProxy(); 
     //request.Proxy.Credentials = CredentialCache.DefaultNetworkCredentials; 
     request.Credentials = new NetworkCredential(_username, _password); 
     Stream rs=(Stream)request.GetResponse().GetResponseStream(); 

     OnStatusChange("CONNECTED: " + path, 0, 0); 

     StreamReader sr = new StreamReader(rs); 
     string strList = sr.ReadToEnd(); 
     string[] lines=null; 

     if (strList.Contains("\r\n")) 
     { 
      lines=strList.Split(new string[] {"\r\n"},StringSplitOptions.None); 
     } 
     else if (strList.Contains("\n")) 
     { 
      lines=strList.Split(new string[] {"\n"},StringSplitOptions.None); 
     } 

     //now decode this string array 

     if (lines==null || lines.Length == 0) 
      return null; 

     foreach(string line in lines) 
     { 
      if (line.Length==0) 
       continue; 
      //parse line 
      Match m= GetMatchingRegex(line); 
      if (m==null) { 
       //failed 
       throw new ApplicationException("Unable to parse line: " + line); 
      } 

      ftpinfo item=new ftpinfo(); 
      item.filename = m.Groups["name"].Value.Trim('\r'); 
      item.path = path; 
      item.size = Convert.ToInt64(m.Groups["size"].Value); 
      item.permission = m.Groups["permission"].Value; 
      string _dir = m.Groups["dir"].Value; 
      if(_dir.Length>0 && _dir != "-") 
      { 
       item.fileType = directoryEntryTypes.directory; 
      } 
      else 
      { 
       item.fileType = directoryEntryTypes.file; 
      } 

      try 
      { 
       item.fileDateTime = DateTime.Parse(m.Groups["timestamp"].Value); 
      } 
      catch 
      { 
       item.fileDateTime = DateTime.MinValue; //null; 
      } 

      files.Add(item); 
     } 

     return files; 
+1

非常感謝你的迴應。工作時,我讀了一次到最後。我不必使用整個代碼,因爲我認爲我必須包含這個庫。再次感謝。 – Habtamu 2013-04-10 10:10:55

1

你迭代到子目錄,前閱讀(和緩存)整體上市,否則頂級請求將之前完成子目錄上市超時。

您可以繼續使用ReadLine,無需使用ReadToEnd並自行分開線路。

void ListFtpDirectory(
    string url, string rootPath, NetworkCredential credentials, List<string> list) 
{ 
    FtpWebRequest listRequest = (FtpWebRequest)WebRequest.Create(url + rootPath); 
    listRequest.Method = WebRequestMethods.Ftp.ListDirectoryDetails; 
    listRequest.Credentials = credentials; 

    List<string> lines = new List<string>(); 

    using (FtpWebResponse listResponse = (FtpWebResponse)listRequest.GetResponse()) 
    using (Stream listStream = listResponse.GetResponseStream()) 
    using (StreamReader listReader = new StreamReader(listStream)) 
    { 
     while (!listReader.EndOfStream) 
     { 
      lines.Add(listReader.ReadLine()); 
     } 
    } 

    foreach (string line in lines) 
    { 
     string[] tokens = 
      line.Split(new[] { ' ' }, 9, StringSplitOptions.RemoveEmptyEntries); 
     string name = tokens[8]; 
     string permissions = tokens[0]; 

     string filePath = rootPath + name; 

     if (permissions[0] == 'd') 
     { 
      ListFtpDirectory(url, filePath + "/", credentials, list); 
     } 
     else 
     { 
      list.Add(filePath); 
     } 
    } 
} 

使用功能,如:

List<string> list = new List<string>(); 
NetworkCredential credentials = new NetworkCredential("user", "mypassword"); 
string url = "ftp://ftp.example.com/"; 
ListFtpDirectory(url, "", credentials, list); 

上述方法的缺點是,它解析服務器特定的房源檢索有關文件和文件夾的信息。上面的代碼需要一個通用的* nix風格的列表。但是許多服務器使用不同的格式。

不幸的是,FtpWebRequest命令不支持MLSD命令,這是在FTP協議中檢索具有文件屬性的目錄列表的唯一便攜方式。


如果你想避免與解析服務器特定的目錄列表格式的煩惱,使用支持MLSD命令和/或解析各種LIST房源格式第三方庫;和遞歸下載。

例如與WinSCP .NET assembly你可以列出整個目錄與該Session.EnumerateRemoteFiles一個電話:

// Setup session options 
SessionOptions sessionOptions = new SessionOptions 
{ 
    Protocol = Protocol.Ftp, 
    HostName = "ftp.example.com", 
    UserName = "user", 
    Password = "mypassword", 
}; 

using (Session session = new Session()) 
{ 
    // Connect 
    session.Open(sessionOptions); 

    // List files 
    IEnumerable<string> list = 
     session.EnumerateRemoteFiles("/", null, EnumerationOptions.AllDirectories). 
     Select(fileInfo => fileInfo.FullName); 
} 

內部,WinSCP賦予使用MLSD命令,如果服務器支持。如果不是,則使用LIST命令並支持數十種不同的列表格式。

(我的WinSCP的作者)

相關問題