C# 解析 FtpWebRequest ListDirectoryDetails 行
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/1013486/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Parsing FtpWebRequest ListDirectoryDetails line
提问by zSynopsis
I need some help with parsing the response from ListDirectoryDetails
in C#.
我需要一些帮助来解析ListDirectoryDetails
C# 中的响应。
I only need the following fields.
我只需要以下字段。
- File Name/Directory Name
- Date Created
- and the File Size.
- 文件名/目录名
- 创建日期
- 和文件大小。
Here's what some of the lines look like when I run ListDirectoryDetails
:
这是我运行时的一些行的样子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
Thanks in advance.
提前致谢。
采纳答案by Ryan Conrad
Not sure if you still need this, but this is the solution i came up with:
不确定你是否还需要这个,但这是我想出的解决方案:
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 );
Match Groups:
比赛组:
- object type:
- d : directory
- - : file
- Array[3] of permissions (rwx-)
- File Size
- Last Modified Date
- Last Modified Time
- File/Directory Name
- 对象类型:
- d:目录
- - : 文件
- 权限数组[3] (rwx-)
- 文件大小
- 最后修改日期
- 上次修改时间
- 文件/目录名称
回答by XCoder8
This is my algorithm to get the File/Dir name, Date Created, Attribute(File/Dir), Size. Hope this helps...
这是我获取文件/目录名称、创建日期、属性(文件/目录)、大小的算法。希望这可以帮助...
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;
}
}
}
回答by Martin Prikryl
For this specific listing, the following code will do:
对于此特定列表,以下代码将执行:
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"));
}
You will get (as of year 2016):
您将获得(截至 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
But, actually trying to parse the listing returned by the ListDirectoryDetails
is not the right way to go.
但是,实际上尝试解析 返回的列表ListDirectoryDetails
并不是正确的方法。
You want to use an FTP client that supports the modern MLSD
command that returns a directory listing in a machine-readable format specified in the RFC 3659. Parsing the human-readable format returned by the ancient LIST
command (used internally by the FtpWebRequest
for its ListDirectoryDetails
method) should be used as the last resort option, when talking to obsolete FTP servers, that do not support the MLSD
command (like the Microsoft IIS FTP server).
您希望使用支持现代MLSD
命令的 FTP 客户端,该命令以RFC 3659 中指定的机器可读格式返回目录列表。在与不支持该命令的过时 FTP 服务器(如 Microsoft IIS FTP 服务器)交谈时,应将解析由古老LIST
命令返回的人类可读格式(由 内部FtpWebRequest
用于其ListDirectoryDetails
方法)作为最后的手段MLSD
.
Many servers use a different format for the LIST
command response. Particularly IIS can use DOS format. See C# class to parse WebRequestMethods.Ftp.ListDirectoryDetails FTP response.
许多服务器对LIST
命令响应使用不同的格式。特别是IIS可以使用DOS格式。请参阅C# 类以解析 WebRequestMethods.Ftp.ListDirectoryDetails FTP 响应。
For example with WinSCP .NET assembly, you can use its Session.ListDirectory
or Session.EnumerateRemoteFiles
methods.
例如,对于WinSCP .NET 程序集,您可以使用它的Session.ListDirectory
或Session.EnumerateRemoteFiles
方法。
They internally use the MLSD
command, but can fall back to the LIST
command and support dozens of different human-readable listing formats.
它们在内部使用该MLSD
命令,但可以回退到该LIST
命令并支持数十种不同的人类可读列表格式。
The returned listing is presented as collection of RemoteFileInfo
instanceswith properties like:
返回的列表显示为具有以下属性的RemoteFileInfo
实例集合:
Name
LastWriteTime
(with correct timezone)Length
FilePermissions
(parsed into individual rights)Group
Owner
IsDirectory
IsParentDirectory
IsThisDirectory
Name
LastWriteTime
(具有正确的时区)Length
FilePermissions
(解析为个人权利)Group
Owner
IsDirectory
IsParentDirectory
IsThisDirectory
(I'm the author of WinSCP)
(我是 WinSCP 的作者)
Most other 3rd party libraries will do the same. Using the FtpWebRequest
classis not reliable for this purpose. Unfortunately, there's no other built-in FTP client in the .NET framework.
大多数其他 3rd 方库也会这样做。为此目的使用FtpWebRequest
该类是不可靠的。不幸的是,.NET 框架中没有其他内置的 FTP 客户端。
回答by Nyerguds
Building on the regex idea of Ryan Conrad, this is my final reading code:
基于Ryan Conrad的正则表达式思想,这是我的最终阅读代码:
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;
}
And the FtpFileInfo class that's filled:
以及填充的 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; }
}