Подтвердить что ты не робот

Класс С# для анализа WebRequestMethods.Ftp.ListDirectoryDetails FTP-ответ

Я создаю службу мониторинга местоположений FTP для новых обновлений и требую возможности анализировать ответ, полученный из ответа FtpWebRequest, используя WebRequestMethods.Ftp.ListDirectoryDetails метод. Было бы довольно легко, если бы все ответы соответствовали одному и тому же формату, но другое программное обеспечение 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

И другие различия наблюдались также, поэтому, вероятно, будет несколько тонких различий, с которыми я еще не сталкивался.

Кто-нибудь знает о полностью управляемом (не требует доступа к внешней dll в Windows) классе С#, который легко справляется с этими ситуациями?

Мне нужно только указать содержимое каталога со следующими данными: имя файла/каталога, последнее обновление или созданная метка времени, имя файла/каталога.

Заранее благодарим за любые предложения, Gavin

4b9b3361

Ответ 1

Одно решение, с которым я столкнулся, - EdtFTPnet

EdtFTPnet, по-видимому, представляет собой довольно функциональное пакетное решение, которое обрабатывает множество разных опций FTP, поэтому идеально.

Это бесплатное решение с открытым исходным кодом, которое я использовал для http://www.ftp2rss.com (маленький инструмент, который мне нужен был, но, возможно, полезен другим).

Ответ 2

Для первого (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) списка, см. мой ответ на строку Parsing FtpWebRequest ListDirectoryDetails.


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

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


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

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

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

  • Name
  • LastWriteTime (с правильным часовым поясом)
  • Length
  • FilePermissions (анализируется на отдельные права)
  • Group
  • Owner
  • IsDirectory
  • IsParentDirectory
  • IsThisDirectory

(Я автор WinSCP)


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

Ответ 3

Я столкнулся с этой же проблемой и создал простое (хотя и не очень надежное) решение с использованием 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);

Затем вы можете извлечь значения из групп захвата с помощью:

        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 может представлять собой год или время временной метки файла. Вам нужно будет разобрать это вручную, ища экземпляр двоеточия: символ, который укажет, что эта группа захвата содержит время, а не год