从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等。我也不能总是获取文件的年份部分。

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

选项B:为了更直接地回答您的问题,我认为问题在于这一行:

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

好像FTP服务器正在使用空格来右对齐文件名。 为了解决这个问题,我们希望调整正则表达式以消耗字段之间的所有空格:

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

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

首先,有一些组件可以从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; } 

尝试

 ListDirectory + GetDateTimestamp 

代替

 ListDirectoryDetails 

为此,您需要检索远程目录列表,包括时间戳。

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

您可以使用的替代方案,.NET框架支持(如其他答案所示):

  • ListDirectoryDetails方法 (FTP LIST命令)检索目录中所有文件的详细信息然后你处理FTP服务器特定格式的细节(* nix格式类似于ls * nix命令是最常见的,缺点是格式可能会随着时间而改变,因为较新的文件使用“May 8 17:48”格式,而旧文件使用“Oct 18 2009”格式

    DOS / Windows格式: C#类解析WebRequestMethods.Ftp.ListDirectoryDe​​tails FTP响应
    * nix格式: 解析FtpWebRequest ListDirectoryDe​​tails行

  • GetDateTimestamp方法 (FTP MDTM命令),用于单独检索每个文件的时间戳。 优点是响应由RFC 3659标准化为YYYYMMDDHHMMSS[.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程序集支持它。

您可以使用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的作者)

这是来自FTPclient源代码的一个exerpt ,它向您展示了他们如何构建他们的。 FtpFileInfo对象。 我无法测试到这一点,确保此刻在所有情况下都可以使用,但也许它会给你一些想法。

  ///  /// Return a detailed directory listing, and also download datetime stamps if specified ///  /// Directory to list, eg /pub/etc /// Boolean: set to True to download the datetime stamp for files /// An FTPDirectory object 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; } ///  /// Obtain datetimestamp for remote file ///  ///  ///  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); }