我正在创建一项服务来监控FTP位置以获取新更新,并且需要能够使用 WebRequestMethods.Ftp.ListDirectoryDetails 解析从 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
还观察到其他差异,因此可能存在一些我尚未遇到的细微差别。
是否有人知道完全托管(不需要访问Windows上的外部DLL)C#类可以无缝地处理这些情况?
我只需要列出目录的内容,其中包含以下详细信息:文件/目录名称,上次更新或创建的时间戳,文件/目录名称。
提前感谢任何建议, 加文
答案 0 :(得分:9)
对于第一个(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)列表,请参阅my answer to Parsing FtpWebRequest ListDirectoryDetails line。
但是,实际上尝试解析ListDirectoryDetails
返回的列表并不是正确的方法。
您希望使用支持现代MLSD
命令的FTP客户端,该命令以RFC 3659中指定的机器可读格式返回目录列表。解析古代LIST
命令返回的人类可读格式(由FtpWebRequest
内部由ListDirectoryDetails
方法使用)应该用作最后的选择,与过时的FTP服务器交谈时,不支持MLSD
命令(如Microsoft IIS FTP服务器)。
例如,使用WinSCP .NET assembly,您可以使用其Session.ListDirectory
或Session.EnumerateRemoteFiles
方法。
他们在内部使用MLSD
命令,但可以回退到LIST
命令并支持许多不同的人类可读列表格式。
返回的商家信息显示为RemoteFileInfo
instances的集合,其中包含以下属性:
Name
LastWriteTime
(使用正确的时区)Length
FilePermissions
(解析为个人权利)Group
Owner
IsDirectory
IsParentDirectory
IsThisDirectory
(我是WinSCP的作者)
大多数其他第三方库也会这样做。使用FtpWebRequest
class并不可靠。不幸的是,.NET框架中没有其他内置的FTP客户端。
答案 1 :(得分:7)
我正面临着同样的问题,并使用正则表达式构建了一个简单的(尽管不是非常强大)解决方案,使用捕获组从每一行解析出相关信息:
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;
有些事情没有注意到:
ftpResponse
变量中描述的格式的目录响应。在我的情况下,我很幸运,每次只访问相同的FTP服务器,因此响应格式不太可能改变。yearTime
变量可以表示文件时间戳的年份或时间。您需要通过查找冒号:字符的实例来手动解析它,该字符将指示此捕获组包含时间而不是年份答案 2 :(得分:4)
我遇到的一个解决方案是EdtFTPnet
EdtFTPnet似乎是一个功能丰富的解决方案,可以处理许多不同的FTP选项,因此非常理想。
这是免费的开源解决方案,我已经用于http://www.ftp2rss.com(我自己需要的一个小工具,但也可能对其他人有用)。
答案 3 :(得分:0)
对于Windows,Unix和Netware平台上的大多数FTP服务器,它包括automatic directory listing parser。
请注意,这是我开发的商业产品。