2012-03-30 168 views
2

我试图获得FTP服务器上的文件列表,然后逐个检查该文件是否存在于本地系统上,以及它是否比较了修改日期和如果ftp文件较新,请下载它。从FTP服务器下载新文件和修改后的文件

private void btnGo_Click(object sender, EventArgs e) 
{ 
    string[] files = GetFileList(); 
    foreach (string file in files) 
    { 
     if (file.Length >= 5) 
     { 
      string uri = "ftp://" + ftpServerIP + "/" + remoteDirectory + "/" + file; 
      Uri serverUri = new Uri(uri); 

      CheckFile(file); 
     } 
    } 
    this.Close(); 
} 

public string[] GetFileList() 
{ 
    string[] downloadFiles; 
    StringBuilder result = new StringBuilder(); 
    WebResponse response = null; 
    StreamReader reader = null; 

    try 
    { 
     FtpWebRequest reqFTP = (FtpWebRequest)FtpWebRequest.Create(new Uri("ftp://" + ftpServerIP + "/" + remoteDirectory)); 
     reqFTP.UseBinary = true; 
     reqFTP.Credentials = new NetworkCredential(ftpUserID, ftpPassword); 
     reqFTP.Method = WebRequestMethods.Ftp.ListDirectoryDetails; 
     reqFTP.Proxy = null; 
     reqFTP.KeepAlive = false; 
     reqFTP.UsePassive = false; 
     response = reqFTP.GetResponse(); 
     reader = new StreamReader(response.GetResponseStream()); 

     string line = reader.ReadLine(); 
     while (line != null) 
     { 
      result.Append(line); 
      result.Append("\n"); 
      line = reader.ReadLine(); 
     } 
     result.Remove(result.ToString().LastIndexOf('\n'), 1); 
     return result.ToString().Split('\n'); 
    } 
    catch 
    { 
     if (reader != null) 
     { 
      reader.Close(); 
     } 
     if (response != null) 
     { 
      response.Close(); 
     } 
     downloadFiles = null; 
     return downloadFiles; 
    } 
} 

private void CheckFile(string file) 
{ 
    string dFile = file; 
    string[] splitDownloadFile = Regex.Split(dFile, " "); 
    string fSize = splitDownloadFile[13]; 
    string fMonth = splitDownloadFile[14]; 
    string fDate = splitDownloadFile[15]; 
    string fTime = splitDownloadFile[16]; 
    string fName = splitDownloadFile[17]; 


    string dateModified = fDate + "/" + fMonth+ "/" + fYear; 

    DateTime lastModifiedDF = Convert.ToDateTime(dateModified); 

    string[] filePaths = Directory.GetFiles(localDirectory); 

    // if there is a file in filePaths that is the same as on the server compare them and then download if file on server is newer 
    foreach (string ff in filePaths) 
    { 

     string[] splitFile = Regex.Split(ff, @"\\"); 

     string fileName = splitFile[2]; 
     FileInfo fouFile = new FileInfo(ff); 
     DateTime lastChangedFF = fouFile.LastAccessTime; 
     if (lastModifiedDF > lastChangedFF) Download(fileName); 
    } 
} 

在检查文件的方法,对每个文件(它们是.exe文件)我不断收到不同的结果,当我分割字符串即一个文件的文件名是在第18栏另一个是在16等。我也不能总是得到文件的年份。

回答

0

选项A:我建议你使用更高级别的FTP客户端库来处理这些细节,有几种可能的选择是:

选项B:为了更直接地回答你的问题,我认为这个问题是这一行:

string[] splitDownloadFile = Regex.Split(dFile, " "); 

这似乎是FTP服务器使用空格右对齐文件名。为了解决这个问题,我们要调整的正则表达式来消费领域之间的所有空白:

string[] splitDownloadFile = Regex.Split(dFile, "\s+"); 

...这里是指一个或多个\ s表示任何空白字符(通常是制表符或空格),+它左边的东西。这不会处理边缘情况,例如其中包含空格的文件名。

+0

这是一个馊主意。我尝试了ftplib和ftps,两者都不稳定,因为它们间歇性地抛出异常。即使我将呼叫置于5次重试循环中,仍然无法使其可靠工作。 ftplib会抛出无法在主线程中捕获的异常,从而使我的Windows服务每隔一小时左右崩溃。我不能说netftp,因为我没有尝试它。我最终使用标准的.NET FtpWebRequest类和非标准的IIS配置(通过端口21的ftps)来使它工作。我最终使用ftplib的解析器来获取目录列表详细信息。 – NightOwl888 2012-12-02 10:12:09

0

这是从FTPclient来源exerpt向您展示他们如何建立他们的。 FtpFileInfo对象。我无法对此进行测试,以确保此时可以在所有情况下都能正常工作,但也许它会给你一些想法。所有的

/// <summary> 
    /// Return a detailed directory listing, and also download datetime stamps if specified 
    /// </summary> 
    /// <param name="directory">Directory to list, e.g. /pub/etc</param> 
    /// <param name="doDateTimeStamp">Boolean: set to True to download the datetime stamp for files</param> 
    /// <returns>An FTPDirectory object</returns> 
    public FTPdirectory ListDirectoryDetail(string directory, bool doDateTimeStamp) 
    { 
     System.Net.FtpWebRequest ftp = GetRequest(GetDirectory(directory)); 
     // Set request to do simple list 
     ftp.Method = System.Net.WebRequestMethods.Ftp.ListDirectoryDetails; 

     string str = GetStringResponse(ftp); 
     // replace CRLF to CR, remove last instance 
     str = str.Replace("\r\n", "\r").TrimEnd('\r'); 
     // split the string into a list 
     FTPdirectory dir = new FTPdirectory(str, _lastDirectory); 

     // download timestamps if requested 
     if (doDateTimeStamp) 
     { 
      foreach (FTPfileInfo fi in dir) 
      { 
       fi.FileDateTime = this.GetDateTimestamp(fi); 
      } 
     } 

     return dir; 
    } 

    /// <summary> 
    /// Obtain datetimestamp for remote file 
    /// </summary> 
    /// <param name="filename"></param> 
    /// <returns></returns> 
    public DateTime GetDateTimestamp(string filename) 
    { 
     string path; 
     if (filename.Contains("/")) 
     { 
      path = AdjustDir(filename); 
     } 
     else 
     { 
      path = this.CurrentDirectory + filename; 
     } 
     string URI = this.Hostname + path; 
     FtpWebRequest ftp = GetRequest(URI); 
     ftp.Method = WebRequestMethods.Ftp.GetDateTimestamp; 
     return this.GetLastModified(ftp); 
    } 
2

首先,有一些组件,您可以获取信息和下载数据从FTP可以在这里找到:http://www.limilabs.com/ftp

我写了获取文件名,并从FTP最后修改日期的一些方法。

这是我如何摆脱线的文件名:

private string GetFtpName(string line) 
{ 
    for (int i = 0; i < 8; i++) 
     line = line.Substring(line.IndexOf(" ")).Trim(); 
    return line; 
} 

这就是我如何从FTP最后修改日期:

private DateTime GetFtpFileDate(string url, ICredentials credential) 
{ 
    FtpWebRequest rd = (FtpWebRequest)WebRequest.Create(url); 
    rd.Method = WebRequestMethods.Ftp.GetDateTimestamp; 
    rd.Credentials = credential; 

    FtpWebResponse response = (FtpWebResponse)rd.GetResponse(); 
    DateTime lmd = response.LastModified; 
    response.Close(); 

    return lmd; 
} 
1

尝试

ListDirectory + GetDateTimestamp 

,而不是

ListDirectoryDetails 
+0

只获取文件名。我需要能够看到修改文件的日期 – Noelle 2012-04-20 14:28:24

+0

@Wellie:对'ListDirectory'返回的每个文件文件使用'GetDateTimestamp'。这将消除字符串状态表示解析问题 – abatishchev 2012-04-20 14:37:33

1

对于这一点,你需要检索远程目录列表,包括时间戳。

不幸的是,使用.NET框架提供的功能没有真正可靠和有效的方法检索时间戳,因为它不支持FTP MLSD命令。命令MLSD以标准化的机器可读格式提供远程目录的列表。命令和格式由RFC 3659标准化。

替代品,你可以使用,这是由.NET框架的支持(如其他答案显示):

  • ListDirectoryDetails method(在FTP LIST命令)来检索目录中的所有文件的详细信息和那么你处理FTP服务器的具体格式的细节(* nix格式类似于ls * nix命令是最常见的,缺点是格式可能随时间而改变,对于较新的文件使用“May 8 17:48”格式并且对于较老的文件使用“Oct 18 2009”格式)

    DOS/Windows格式: C# class to parse WebRequestMethods.Ftp.ListDirectoryDetails FTP response
    * nix的格式:Parsing FtpWebRequest ListDirectoryDetails line

  • GetDateTimestamp method(一个FTP MDTM命令)来个别地检索每个文件的时间戳。优点是响应由RFC 3659YYYYMMDDHHMMSS[.sss]标准化。缺点是你必须为每个文件发送一个单独的请求,效率很低。

    const string uri = "ftp://ftp.example.com/remote/path/file.txt"; 
    FtpWebRequest request = (FtpWebRequest)WebRequest.Create(uri); 
    request.Method = WebRequestMethods.Ftp.GetDateTimestamp; 
    FtpWebResponse response = (FtpWebResponse)request.GetResponse(); 
    Console.WriteLine("{0} {1}", uri, response.LastModified); 
    

另外,您可以使用支持现代MLSD命令第三方FTP客户端实现。

例如WinSCP .NET assembly支持。

您可以使用Session.ListDirectorySession.EnumerateRemoteFiles方法并读取返回集合中文件的RemoteFileInfo.LastWriteTime

或者更简单,你可以使用Session.SynchronizeDirectories自动有库下载(同步)修改后的文件:

// 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); 

    // Synchronize files 
    session.SynchronizeDirectories(
     SynchronizationMode.Local, @"d:\www", "/remote/path", false).Check(); 
} 

(我的WinSCP的作者)