C# класс для анализа 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) класс C#, который легко обрабатывает эти ситуации?
Мне нужно только перечислить содержимое каталога со следующими данными: имя файла / каталога, отметка времени последнего обновления или создания, имя файла / каталога.
Заранее спасибо за любые предложения, Гэвин
4 ответа
Одно решение, с которым я столкнулся, - EdtFTPnet
EdtFTPnet, кажется, довольно функциональное решение, которое обрабатывает множество различных параметров FTP, поэтому идеально подходит.
Это бесплатное решение с открытым исходным кодом, которое я использовал для http://www.ftp2rss.com/ (небольшой инструмент, который мне был нужен сам, но подумал, что может быть полезен и для других).
Для первого (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
команда (например, сервер Microsoft IIS FTP).
Например, для сборки WinSCP .NET вы можете использовать ее Session.ListDirectory
или же Session.EnumerateRemoteFiles
методы.
Они внутренне используют MLSD
команда, но может вернуться к LIST
командование и поддержка десятков различных удобочитаемых форматов списков.
Возвращенный список представлен как коллекция RemoteFileInfo
экземпляры со свойствами, такими как:
Name
LastWriteTime
(с правильным часовым поясом)Length
FilePermissions
(разбирается на индивидуальные права)Group
Owner
IsDirectory
IsParentDirectory
IsThisDirectory
(Я автор WinSCP)
Большинство других сторонних библиотек будут делать то же самое. С использованием FtpWebRequest
класс не надежен для этой цели. К сожалению, в.NET Framework нет другого встроенного FTP-клиента.
Я сталкиваюсь с этой же проблемой и создал простое (хотя и не очень надежное) решение с использованием регулярных выражений для анализа соответствующей информации из каждой строки с использованием групп захвата:
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
переменная может представлять ЛИБО год или время метки времени файла. Вам нужно будет проанализировать это вручную, ища экземпляр символа двоеточие: символ, который будет указывать, что эта группа захвата содержит время, а не год
Взгляните на FTP-клиент Ftp.dll.
Он включает в себя автоматический анализатор списков каталогов для большинства FTP-серверов на платформах Windows, Unix и Netware.
Обратите внимание, что это коммерческий продукт, который я разработал.