Парсинг линии FtpWebRequest ListDirectoryDetails
мне нужна помощь с разбором ответа от ListDirectoryDetails
в C#.
мне нужны только следующие поля.
- Имя Файла/Имя Директории
- Дата Создания
- и размер файла.
вот как выглядят некоторые строки, когда я бегу 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
спасибо заранее.
4 ответов
Не уверен, что вам все еще это нужно, но это решение, которое я придумал:
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 );
Матч Группы:
- тип объекта :
- d: каталог
- - : file
- массив [3] разрешений (rwx-)
- Размер Файла
- Дата Последнего Изменения
- Последние Изменения
- Имя Файла/Каталога
для этого конкретного списка, следующий код будет делать:
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-клиент, который поддерживает modern MLSD
команда, которая возвращает список каталогов в машиночитаемом формате, указанном в RFC 3659. Разбор удобочитаемого формата возвращенный древним LIST
команда (используется внутри FtpWebRequest
для своего ListDirectoryDetails
метод) следует использовать в качестве последнего варианта, при разговоре с устаревшими FTP-серверами, которые не поддерживают MLSD
команда (например, FTP-сервер Microsoft IIS).
многие серверы используют другой формат для LIST
"команда-ответ". В частности, IIS может использовать формат DOS. См.класс C# для разбора WebRequestMethods.Программа передачи файлов.ListDirectoryDetails ФТП ответ.
например WinSCP .NET assembly, вы можете использовать Session.ListDirectory
или Session.EnumerateRemoteFiles
методы.
они внутренне использовать MLSD
команда, но может вернуться к LIST
команда и поддержка десятков различных удобочитаемых форматов листинга.
возвращенный список представлен как коллекция RemoteFileInfo
экземпляров свойства например:
Name
-
LastWriteTime
(С правильным часовым поясом) Length
-
FilePermissions
(разбирается на индивидуальные права) Group
Owner
IsDirectory
IsParentDirectory
IsThisDirectory
(я автор WinSCP)
большинство других сторонних библиотек сделают то же самое. С помощью FtpWebRequest
класс не является надежным для этой цели. К сожалению, в .NET framework нет другого встроенного FTP-клиента.
Это мой алгоритм для получения имени файла / Dir, даты создания, атрибута (File / Dir), размера. Надеюсь, это поможет...
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;
}
}
}
основываясь на идее регулярного выражения Райан Конрад, Это мой последний код чтения:
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; }
}