C# 解析 FtpWebRequest ListDirectoryDe​​tails 行

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/1013486/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-06 05:32:56  来源:igfitidea点击:

Parsing FtpWebRequest ListDirectoryDetails line

c#parsingftpftpwebrequest

提问by zSynopsis

I need some help with parsing the response from ListDirectoryDetailsin C#.

我需要一些帮助来解析ListDirectoryDetailsC# 中的响应。

I only need the following fields.

我只需要以下字段。

  • File Name/Directory Name
  • Date Created
  • and the File Size.
  • 文件名/目录名
  • 创建日期
  • 和文件大小。

Here's what some of the lines look like when I run ListDirectoryDetails:

这是我运行时的一些行的样子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

Thanks in advance.

提前致谢。

采纳答案by Ryan Conrad

Not sure if you still need this, but this is the solution i came up with:

不确定你是否还需要这个,但这是我想出的解决方案:

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 );

Match Groups:

比赛组:

  1. object type:
    • d : directory
    • - : file
  2. Array[3] of permissions (rwx-)
  3. File Size
  4. Last Modified Date
  5. Last Modified Time
  6. File/Directory Name
  1. 对象类型:
    • d:目录
    • - : 文件
  2. 权限数组[3] (rwx-)
  3. 文件大小
  4. 最后修改日期
  5. 上次修改时间
  6. 文件/目录名称

回答by XCoder8

This is my algorithm to get the File/Dir name, Date Created, Attribute(File/Dir), Size. Hope this helps...

这是我获取文件/目录名称、创建日期、属性(文件/目录)、大小的算法。希望这可以帮助...

        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;
                }
            }
        }

回答by Martin Prikryl

For this specific listing, the following code will do:

对于此特定列表,以下代码将执行:

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"));
}

You will get (as of year 2016):

您将获得(截至 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


But, actually trying to parse the listing returned by the ListDirectoryDetailsis not the right way to go.

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

You want to use an FTP client that supports the modern MLSDcommand that returns a directory listing in a machine-readable format specified in the RFC 3659. Parsing the human-readable format returned by the ancient LISTcommand (used internally by the FtpWebRequestfor its ListDirectoryDetailsmethod) should be used as the last resort option, when talking to obsolete FTP servers, that do not support the MLSDcommand (like the Microsoft IIS FTP server).

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

Many servers use a different format for the LISTcommand response. Particularly IIS can use DOS format. See C# class to parse WebRequestMethods.Ftp.ListDirectoryDetails FTP response.

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



For example with WinSCP .NET assembly, you can use its Session.ListDirectoryor Session.EnumerateRemoteFilesmethods.

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

They internally use the MLSDcommand, but can fall back to the LISTcommand and support dozens of different human-readable listing formats.

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

The returned listing is presented as collection of RemoteFileInfoinstanceswith properties like:

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

  • Name
  • LastWriteTime(with correct timezone)
  • Length
  • FilePermissions(parsed into individual rights)
  • Group
  • Owner
  • IsDirectory
  • IsParentDirectory
  • IsThisDirectory
  • Name
  • LastWriteTime(具有正确的时区)
  • Length
  • FilePermissions(解析为个人权利)
  • Group
  • Owner
  • IsDirectory
  • IsParentDirectory
  • IsThisDirectory

(I'm the author of WinSCP)

(我是 WinSCP 的作者)



Most other 3rd party libraries will do the same. Using the FtpWebRequestclassis not reliable for this purpose. Unfortunately, there's no other built-in FTP client in the .NET framework.

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

回答by Nyerguds

Building on the regex idea of Ryan Conrad, this is my final reading code:

基于Ryan Conrad的正则表达式思想,这是我的最终阅读代码:

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;
}

And the FtpFileInfo class that's filled:

以及填充的 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; }
}