parsingFtpWebRequest的ListDirectoryDe​​tails行

我需要一些帮助parsing来自C#中的ListDirectoryDetails响应。

我只需要以下字段。

  • 文件名/目录名称
  • 创builddate
  • 和文件大小。

当我运行ListDirectoryDetails时,下面是一些行的样子:

 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 

提前致谢。

不知道你是否仍然需要这个,但这是我想出的解决scheme:

 Regex regex = new Regex ( @"^([d-])([rwxt-]{3}){3}\s+\d{1,}\s+.*?(\d{1,})\s+(\w+\s+\d{1,2}\s+(?:\d{4})?)(\d{1,2}:\d{2})?\s+(.+?)\s?$", RegexOptions.Compiled | RegexOptions.Multiline | RegexOptions.IgnoreCase | RegexOptions.IgnorePatternWhitespace ); 

比赛组:

  1. 对象types:
    • d:目录
    • – :文件
  2. 数组[3]权限(rwx-)
  3. 文件大小
  4. 上次修改date
  5. 上次修改时间
  6. 文件/目录名称

对于这个具体的清单,下面的代码将做到:

 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 = @"^([\w-]+)\s+(\d+)\s+(\w+)\s+(\w+)\s+(\d+)\s+" + @"(\w+\s+\d+\s+\d+|\w+\s+\d+\s+\d+:\d+)\s+(.+)$"; Regex regex = new Regex(pattern); IFormatProvider culture = CultureInfo.GetCultureInfo("en-us"); string[] hourMinFormats = new[] { "MMM dd HH:mm", "MMM dd H:mm", "MMM d HH:mm", "MMM d H:mm" }; string[] yearFormats = new[] { "MMM dd yyyy", "MMM d yyyy" }; while (!reader.EndOfStream) { string line = reader.ReadLine(); Match match = regex.Match(line); string permissions = match.Groups[1].Value; int inode = int.Parse(match.Groups[2].Value, culture); string owner = match.Groups[3].Value; string group = match.Groups[4].Value; long size = long.Parse(match.Groups[5].Value, culture); DateTime modified; string s = Regex.Replace(match.Groups[6].Value, @"\s+", " "); if (s.IndexOf(':') >= 0) { modified = DateTime.ParseExact(s, hourMinFormats, culture, DateTimeStyles.None); } else { modified = DateTime.ParseExact(s, yearFormats, culture, DateTimeStyles.None); } string name = match.Groups[7].Value; Console.WriteLine( "{0,-16} permissions = {1} size = {2, 9} modified = {3}", name, permissions, size, modified.ToString("yyyy-MM-dd HH:mm")); } 

你会得到(截至2016年):

 bin permissions = d--x--x--x size = 4096 modified = 2002-03-07 00:00 TEST.TXT permissions = -rw-r--r-- size = 659450 modified = 2016-06-15 05:07 TEST03-05.TXT permissions = -rw-r--r-- size = 101786380 modified = 2008-09-08 00:00 dropoff permissions = drwxrwxr-x size = 4096 modified = 2016-05-06 12:24 

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

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

许多服务器对LIST命令响应使用不同的格式。 特别是IIS可以使用DOS格式。 请参阅C#类来parsingWebRequestMethods.Ftp.ListDirectoryDe​​tails FTP响应 。


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

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

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

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

(我是WinSCP的作者)


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

这是我的algorithm来获取文件/目录名称,创builddate,属性(文件/目录),大小。 希望这可以帮助…

  FtpWebRequest _fwr = FtpWebRequest.Create(uri) as FtpWebRequest _fwr.Credentials = cred; _fwr.UseBinary = true; _fwr.UsePassive = true; _fwr.KeepAlive = true; _fwr.Method = WebRequestMethods.Ftp.ListDirectoryDetails; StreamReader _sr = new StreamReader(_fwr.GetResponse().GetResponseStream()); List<object> _dirlist = new List<object>(); List<object> _attlist = new List<object>(); List<object> _datelist = new List<object>(); List<long> _szlist = new List<long>(); while (!_sr.EndOfStream) { string[] buf = _sr.ReadLine().Split(' '); //string Att, Dir; int numcnt = 0, offset = 4; ; long sz = 0; for (int i = 0; i < buf.Length; i++) { //Count the number value markers, first before the ftp markers and second //the file size. if (long.TryParse(buf[i], out sz)) numcnt++; if (numcnt == 2) { //Get the attribute string cbuf = "", dbuf = "", abuf = ""; if (buf[0][0] == 'd') abuf = "Dir"; else abuf = "File"; //Get the Date if (!buf[i+3].Contains(':')) offset++; for (int j = i + 1; j < i + offset; j++) { dbuf += buf[j]; if (j < buf.Length - 1) dbuf += " "; } //Get the File/Dir name for (int j = i + offset; j < buf.Length; j++) { cbuf += buf[j]; if (j < buf.Length - 1) cbuf += " "; } //Store to a list. _dirlist.Add(cbuf); _attlist.Add(abuf); _datelist.Add(dbuf); _szlist.Add(sz); offset = 0; break; } } } 

基于Ryan Conrad的正则expression式,这是我最后的阅读代码:

 protected static Regex m_FtpListingRegex = new Regex(@"^([d-])((?:[rwxt-]{3}){3})\s+(\d{1,})\s+(\w+)?\s+(\w+)?\s+(\d{1,})\s+(\w+)\s+(\d{1,2})\s+(\d{4})?(\d{1,2}:\d{2})?\s+(.+?)\s?$", RegexOptions.Compiled | RegexOptions.Multiline | RegexOptions.IgnoreCase | RegexOptions.IgnorePatternWhitespace); protected static readonly String Timeformat = "MMM dd yyyy HH:mm"; /// <summary> /// Handles file info given in the form of a string in standard unix ls output format. /// </summary> /// <param name="filesListing">The file listing string.</param> /// <returns>A list of FtpFileInfo objects</returns> public static List<FtpFileInfo> GetFilesListFromFtpListingUnix(String filesListing) { List<FtpFileInfo> files = new List<FtpFileInfo>(); MatchCollection matches = m_FtpListingRegex.Matches(filesListing); if (matches.Count == 0 && filesListing.Trim('\r','\n','\t',' ').Length != 0) return null; // parse error. Could throw some kind of exception here too. foreach (Match match in matches) { FtpFileInfo fileInfo = new FtpFileInfo(); Char dirchar = match.Groups[1].Value.ToLowerInvariant()[0]; fileInfo.IsDirectory = dirchar == 'd'; fileInfo.Permissions = match.Groups[2].Value.ToCharArray(); // No clue what "inodes" actually means... Int32 inodes; fileInfo.NrOfInodes = Int32.TryParse(match.Groups[3].Value, out inodes) ? inodes : 1; fileInfo.User = match.Groups[4].Success ? match.Groups[4].Value : null; fileInfo.Group = match.Groups[5].Success ? match.Groups[5].Value : null; Int64 fileSize; Int64.TryParse(match.Groups[6].Value, out fileSize); fileInfo.FileSize = fileSize; String month = match.Groups[7].Value; String day = match.Groups[8].Value.PadLeft(2, '0'); String year = match.Groups[9].Success ? match.Groups[9].Value : DateTime.Now.Year.ToString(CultureInfo.InvariantCulture); String time = match.Groups[10].Success ? match.Groups[10].Value.PadLeft(5, '0') : "00:00"; String timeString = month + " " + day + " " + year + " " + time; DateTime lastModifiedDate; if (!DateTime.TryParseExact(timeString, Timeformat, CultureInfo.InvariantCulture, DateTimeStyles.None, out lastModifiedDate)) lastModifiedDate = DateTime.MinValue; fileInfo.LastModifiedDate = lastModifiedDate; fileInfo.FileName = match.Groups[11].Value; files.Add(fileInfo); } return files; } 

和填充的FtpFileInfo类:

 public class FtpFileInfo { public Boolean IsDirectory { get; set; } public Char[] Permissions { get; set; } public Int32 NrOfInodes { get; set; } public String User { get; set; } public String Group { get; set; } public Int64 FileSize { get; set; } public DateTime LastModifiedDate { get; set; } public String FileName { get; set; } }