C#类解析WebRequestMethods.Ftp.ListDirectoryDe​​tails FTP响应

Gav*_*vin 20 .net c# ftp ftpwebrequest

我正在创建一个服务来监视FTP位置以获取新更新,并且需要能够使用WebRequestMethods.Ftp.ListDirectoryDe​​tails方法解析从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
Run Code Online (Sandbox Code Playgroud)

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

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
Run Code Online (Sandbox Code Playgroud)

并且还观察到其他差异,因此可能存在一些我尚未遇到的细微差别.

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

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

提前感谢任何建议,加文

Mar*_*ryl 10

对于第一个(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"));
}
Run Code Online (Sandbox Code Playgroud)

你会得到:

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
Run Code Online (Sandbox Code Playgroud)

对于其他(*nix)列表,请参阅我对Parsing FtpWebRequest ListDirectoryDe​​tails行的回答.


但是,实际上试图解析返回的列表ListDirectoryDetails并不是正确的方法.

您希望使用支持现代MLSD命令的FTP客户端,该命令以RFC 3659中指定的机器可读格式返回目录列表.解析古代LIST命令返回的人类可读格式(FtpWebRequest由其ListDirectoryDetails方法在内部使用)应当作为最后的选择,在与过时的FTP服务器交谈时,不支持该MLSD命令(如Microsoft IIS FTP服务器) .


例如,使用WinSCP .NET程序集,您可以使用它Session.ListDirectorySession.EnumerateRemoteFiles方法.

他们在内部使用该MLSD命令,但可以回退到LIST命令并支持许多不同的人类可读列表格式.

返回的列表显示为具有以下属性的RemoteFileInfo实例集合:

  • Name
  • LastWriteTime (使用正确的时区)
  • Length
  • FilePermissions (解析为个人权利)
  • Group
  • Owner
  • IsDirectory
  • IsParentDirectory
  • IsThisDirectory

(我是WinSCP的作者)


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


小智 8

我正面临着同样的问题,并使用Regex构建了一个简单的(虽然不是非常强大)解决方案,使用捕获组从每一行解析出相关信息:

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);
Run Code Online (Sandbox Code Playgroud)

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

        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;
Run Code Online (Sandbox Code Playgroud)

有些事情没有注意到:

  • 这仅适用于具有上述ftpResponse变量中描述的格式的目录响应.在我的情况下,我很幸运每次只访问相同的FTP服务器,因此响应格式不太可能改变.
  • yearTime变量可以表示的年份或文件的时间戳的时间.您需要通过查找冒号:字符的实例来手动解析它,该字符将指示此捕获组包含时间而不是年份


Gav*_*vin 4

我遇到的一种解决方案是EdtFTPnet

EdtFTPnet 似乎是一个功能丰富的解决方案,可以处理许多不同的 FTP 选项,因此非常理想。

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