C#类来parsingWebRequestMethods.Ftp.ListDirectoryDe​​tails FTP响应

我正在创build一个服务来监视FTP位置以获得新的更新,并需要使用WebRequestMethods.Ftp.ListDirectoryDe​​tails方法来parsing从FtpWebRequest响应返回的响应。 如果所有的响应遵循相同的格式,这将是相当容易的,但不同的FTP服务器软件提供不同的响应格式。

例如,可能会返回:

08-10-11 12:02PM <DIR> Version2 06-25-09 02:41PM 144700153 image34.gif 06-25-09 02:51PM 144700153 updates.txt 11-04-10 02:45PM 144700214 digger.tif 

另一台服务器可能会返回:

 d--x--x--x 2 ftp ftp 4096 Mar 07 2002 bin -rw-r--r-- 1 ftp ftp 659450 Jun 15 05:07 TEST.TXT -rw-r--r-- 1 ftp ftp 101786380 Sep 08 2008 TEST03-05.TXT drwxrwxr-x 2 ftp ftp 4096 May 06 12:24 dropoff 

而且还观察到其他差异,所以可能会有一些细微的差别,我还没有遇到。

有谁知道完全托pipe(不需要访问Windows上的外部DLL)C#类,无缝处理这些情况?

我只需要列出具有以下详细信息的目录的内容:文件/目录名称,上次更新或创build的时间戳,文件/目录名称。

提前感谢任何build议,加文

对于第一个(DOS / Windows)列表,这个代码将执行:

 FtpWebRequest request = (FtpWebRequest)WebRequest.Create("ftp://ftp.example.com/"); request.Credentials = new NetworkCredential("user", "password"); request.Method = WebRequestMethods.Ftp.ListDirectoryDetails; StreamReader reader = new StreamReader(request.GetResponse().GetResponseStream()); string pattern = @"^(\d+-\d+-\d+\s+\d+:\d+(?:AM|PM))\s+(<DIR>|\d+)\s+(.+)$"; Regex regex = new Regex(pattern); IFormatProvider culture = CultureInfo.GetCultureInfo("en-us"); while (!reader.EndOfStream) { string line = reader.ReadLine(); Match match = regex.Match(line); DateTime modified = DateTime.ParseExact( match.Groups[1].Value, "MM-dd-yy hh:mmtt", culture, DateTimeStyles.None); long size = (match.Groups[2].Value != "<DIR>") ? long.Parse(match.Groups[2].Value) : 0; string name = match.Groups[3].Value; Console.WriteLine( "{0,-16} size = {1,9} modified = {2}", name, size, modified.ToString("yyyy-MM-dd HH:mm")); } 

你会得到:

 Version2 size = 0 modified = 2011-08-10 12:02 image34.gif size = 144700153 modified = 2009-06-25 14:41 updates.txt size = 144700153 modified = 2009-06-25 14:51 digger.tif size = 144700214 modified = 2010-11-04 14:45 

对于其他(* nix)列表,请参阅parsingFtpWebRequest ListDirectoryDe​​tails行的答案 。


但是,实际上试图parsingListDirectoryDetails返回的ListDirectoryDetails是不正确的。

您希望使用支持现代MLSD命令的FTP客户端,该命令返回RFC 3659中指定的机器可读格式的目录列表。 当与不支持MLSD命令的废弃FTP服务器通话时,应该使用parsing由古代LIST命令返回的可读格式(由FtpWebRequest在其ListDirectoryDetails方法内部使用)作为最后的选项,如Microsoft IIS FTP服务器)。


例如对于WinSCP .NET程序集 ,您可以使用其Session.ListDirectorySession.EnumerateRemoteFiles方法。

他们在内部使用MLSD命令,但可以回退到LIST命令并支持数十种不同的可读格式的列表格式。

返回的列表是作为具有以下属性的RemoteFileInfo实例的集合呈现的:

  • Name
  • LastWriteTime (带有正确的时区)
  • Length
  • FilePermissions (parsing成个人权利)
  • Group
  • Owner
  • IsDirectory
  • IsParentDirectory
  • IsThisDirectory

(我是WinSCP的作者)


大多数其他第三方库也会这样做。 为此,使用FtpWebRequest类是不可靠的。 不幸的是,.NET框架中没有其他内置的FTP客户端。

我面临着同样的问题,并使用正则expression式构build了一个简单的(虽然不是非常强大的)解决scheme,使用捕获组parsing每行的相关信息:

 public static Regex FtpListDirectoryDetailsRegex = new Regex(@".*(?<month>(Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec))\s*(?<day>[0-9]*)\s*(?<yearTime>([0-9]|:)*)\s*(?<fileName>.*)", RegexOptions.Compiled | RegexOptions.IgnoreCase); 

然后您可以通过以下方式从捕获组中提取值:

  string ftpResponse = "-r--r--r-- 1 ftp ftp 0 Nov 19 11:08 aaa.txt"; Match match = FtpListDirectoryDetailsRegex.Match(ftpResponse); string month = match.Groups["month"].Value; string day = match.Groups["day"].Value; string yearTime = match.Groups["yearTime"].Value; string fileName = match.Groups["fileName"].Value; 

有些东西没有注意到:

  • 这只适用于上面ftpResponsevariables中描述的格式的目录响应。 在我的情况下,我很幸运,每次只能访问同一个FTP服务器,所以响应格式不太可能改变。
  • yearTimevariables可以表示文件时间戳的年份或时间。 您将需要通过查找冒号的一个实例来手动parsing:character将指示此捕获组包含一个时间而不是年份

我遇到的一个解决scheme是EdtFTPnet

EdtFTPnet似乎是一个function丰富的解决scheme,可处理大量不同的FTP选项,因此非常理想。

这是免费的开源解决scheme,我已经为http://www.ftp2rss.com (我需要一个自己的小工具,但其他人也可能有用)。

看看Ftp.dll FTP客户端 。

它包括Windows,Unix和Netware平台上大多数FTP服务器的自动目录列表parsing器 。

请注意,这是我开发的商业产品。