Вопрос по c#, parsing – Разбор строки FtpWebRequest ListDirectoryDetails

10

Мне нужна помощь с разбором ответа отListDirectoryDetails в C #.

Мне нужны только следующие поля.

File Name/Directory Name Date Created and the File Size.

Вот как выглядят некоторые строки, когда я бегуListDirectoryDetails:

<code>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
</code>

Заранее спасибо.

Ваш Ответ

4   ответа
1

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

И класс 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; }
}
23

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

Группы соответствия:

object type: d : directory - : file Array[3] of permissions (rwx-) File Size Last Modified Date Last Modified Time File/Directory Name
если год измененной даты является текущим годом, то он показывает только MMM dd и hh: mm, но если он по сравнению с предыдущим годом, то он показывает фактический год, но без времени.
regexr.com?36qpk классное место, чтобы увидеть ваше регулярное выражение в действии
Великий Regex, добавил имена для всех групп захвата, чтобы сделать его более понятным при разборе ... Как ftpd, который использует этот формат, показывает годы в дате изменения?
К сожалению, это должно быть "ЧЧ: мм", конечно. Во всяком случае, мой последний адаптированный регулярное выражение было@"^([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?$"
С группами: ^ (? & Lt; fileordir & gt; [d -]) (? & Lt; attribs & gt; [rwxt -] {3}) {3} \ s + \ d {1,} \ s +. *? (? & Lt; filesize & gt ; \ д {1,}) \ s + (& л; дата & GT; \ W + \ s + \ д {1,2} \ s + (:? \ д {4})??) (& л; yearortime & GT; \ д {1 , 2}: \ d {2})? \ S + (? & Lt; имя файла & gt;. +?) \ S? $ Если год совпадает, то он покажет время, иначе он покажет год. Это по замыслу. Если вам нужна точная временная метка, используйте WebRequestMethods.Ftp.GetDateTimestamp.
1

даты создания, атрибута (файла / каталога), размера. Надеюсь это поможет...

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

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

Но на самом деле пытается разобрать список, возвращенныйListDirectoryDetails это не правильный путь.

Вы хотите использовать FTP-клиент, который поддерживает современныйMLSD команда, которая возвращает список каталогов в машиночитаемом формате, указанном вRFC 3659, Разбор читаемого человеком формата, возвращаемого древнимиLIST команда (используется внутриFtpWebRequest для егоListDirectoryDetails метод) следует использовать в качестве крайней меры при обращении к устаревшим FTP-серверам, которые не поддерживаютMLSD команда (как FTP-сервер Microsoft IIS).

Многие серверы используют другой формат дляLIST ответ команды. В частности, IIS может использовать формат DOS. УвидетьC # класс для анализа WebRequestMethods.Ftp.ListDirectoryDetails FTP-ответ.

Например сСборка WinSCP .NETВы можете использовать егоSession.ListDirectory или жеSession.EnumerateRemoteFiles методы.

Они внутренне используютMLSD команда, но может вернуться кLIST командование и поддержка десятков различных удобочитаемых форматов списков.

Возвращенный список представлен как коллекцияRemoteFileInfo instances со свойствами как:

Name LastWriteTime (with correct timezone) Length FilePermissions (parsed into individual rights) Group Owner IsDirectory IsParentDirectory IsThisDirectory

(I'm the author of WinSCP)

Большинство других сторонних библиотек будут делать то же самое. С использованиемFtpWebRequest class не является надежным для этой цели. К сожалению, в .NET Framework нет другого встроенного FTP-клиента.

Похожие вопросы