Класс С# для анализа 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
Ответы
Ответ 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
может представлять собой год или время временной метки файла. Вам нужно будет разобрать это вручную, ища экземпляр двоеточия: символ, который укажет, что эта группа захвата содержит время, а не год
Ответ 4
Посмотрите FTP-клиент Ftp.dll.
Он включает в себя автоматический парсер списков каталогов для большинства FTP-серверов на платформах Windows, Unix и Netware.
Обратите внимание, что это коммерческий продукт, который я разработал.