解析 FtpWebRequest ListDirectoryDetails 行
-
06-07-2019 - |
题
我需要一些帮助来解析来自的响应 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
提前致谢。
解决方案
不确定您是否还需要这个,但这是我想出的解决方案:
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:目录
- - :文件
- 权限数组[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 客户端 MLSD
命令以机器可读格式返回目录列表 RFC 3659. 。解析古代返回的人类可读格式 LIST
命令(由内部使用 FtpWebRequest
为其 ListDirectoryDetails
方法)应用作最后的手段选项,当与过时的 FTP 服务器通信时,不支持 MLSD
命令(如 Microsoft IIS FTP 服务器)。
许多服务器使用不同的格式 LIST
命令响应。特别是IIS可以使用DOS格式。看 用于解析 WebRequestMethods.Ftp.ListDirectoryDetails FTP 响应的 C# 类.
例如与 WinSCP .NET 程序集, ,你可以使用它的 Session.ListDirectory
或者 Session.EnumerateRemoteFiles
方法。
他们在内部使用 MLSD
命令,但可以回退到 LIST
命令并支持数十种不同的人类可读的列表格式。
返回的列表显示为集合 RemoteFileInfo
实例 具有如下属性:
Name
LastWriteTime
(具有正确的时区)Length
FilePermissions
(解析为个人权利)Group
Owner
IsDirectory
IsParentDirectory
IsThisDirectory
(我是WinSCP的作者)
大多数其他第三方库也会这样做。使用 FtpWebRequest
班级 对于此目的来说并不可靠。不幸的是,.NET 框架中没有其他内置的 FTP 客户端。
这是我获取文件/目录名称、创建日期、属性(文件/目录)、大小的算法。希望这可以帮助...
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; }
}