https://netftp.codeplex.com/
/// <summary>
/// Gets a file listing from the server. Each FtpListItem object returned
/// contains information about the file that was able to be retrieved. If
/// a DateTime property is equal to DateTime.MinValue then it means the
/// date in question was not able to be retrieved. If the Size property
/// is equal to 0 then it means the size of the object could also not
/// be retrieved.
/// 读取文件或文件夹
/// </summary>
/// <param name="path">The path of the directory to list</param>
/// <param name="options">Options that dictacte how a list is performed and what information is gathered.根据选项读取文件或文件夹或其文件的属性</param>
/// <returns>An array of FtpListItem objects</returns>
/// <example><code source="..\Examples\GetListing.cs" lang="cs" /></example>
public FtpListItem[] GetListing(string path, FtpListOption options) {
FtpListItem item = null;
List<FtpListItem> lst = new List<FtpListItem>();
List<string> rawlisting = new List<string>();
string listcmd = null;
string pwd = GetWorkingDirectory();
string buf = null;
if (path == null || path.Trim().Length == 0) {
pwd = GetWorkingDirectory();
if (pwd != null && pwd.Trim().Length > 0)
path = pwd;
else
path = "./";
}
else if (!path.StartsWith("/") && pwd != null && pwd.Trim().Length > 0) {
if (path.StartsWith("./"))
path = path.Remove(0, 2);
path = string.Format("{0}/{1}", pwd, path).GetFtpPath();
}
// MLSD provides a machine parsable format with more
// accurate information than most of the UNIX long list
// formats which translates to more effcient file listings
// so always prefer MLSD over LIST unless the caller of this
// method overrides it with the ForceList option
// !=
if ((options & FtpListOption.ForceList) == FtpListOption.ForceList && HasFeature(FtpCapability.MLSD))
{
listcmd = "MLSD";
}
else
{
if ((options & FtpListOption.UseLS) == FtpListOption.UseLS)
{
listcmd = "LS";
}
else if ((options & FtpListOption.NameList) == FtpListOption.NameList)
{
listcmd = "NLST"; //读取文件名
}
else
{
string listopts = "";
listcmd = "LIST"; //读取所有文件夹文件
if ((options & FtpListOption.AllFiles) == FtpListOption.AllFiles)
listopts += "a";
if ((options & FtpListOption.Recursive) == FtpListOption.Recursive)
listopts += "R";
if (listopts.Length > 0)
listcmd += " -" + listopts;
}
}
if((options & FtpListOption.NoPath) != FtpListOption.NoPath)
{
listcmd = string.Format("{0} {1}", listcmd, path.GetFtpPath());
}
lock (m_lock)
{
Execute("TYPE I");
//NLST /htdocs 读文件
// read in raw file listing MLSD /htdocs
using (FtpDataStream stream = OpenDataStream(listcmd, 0)) {
try {
while ((buf = stream.ReadLine(Encoding)) != null) {
if (buf.Length > 0)
{
rawlisting.Add(buf);
FtpTrace.WriteLine(buf);
}
//rawlisting.Add(buf);
//FtpTrace.WriteLine(buf);
}
}
finally {
stream.Close();
}
}
}
//根据上一个循环来读文件或文件夹的属性
for (int i = 0; i < rawlisting.Count; i++) {
buf = rawlisting[i];
if ((options & FtpListOption.NameList) == FtpListOption.NameList) {
// if NLST was used we only have a file name so
// there is nothing to parse.
item = new FtpListItem() {
FullName = buf
};
if (DirectoryExists(item.FullName))
item.Type = FtpFileSystemObjectType.Directory;
else
item.Type = FtpFileSystemObjectType.File;
lst.Add(item);
}
else {
// if this is a result of LIST -R then the path will be spit out
// before each block of objects
if (listcmd.StartsWith("LIST") && (options & FtpListOption.Recursive) == FtpListOption.Recursive) {
if (buf.StartsWith("/") && buf.EndsWith(":")) {
path = buf.TrimEnd(':');
continue;
}
}
// if the next line in the listing starts with spaces
// it is assumed to be a continuation of the current line
if (i + 1 < rawlisting.Count && (rawlisting[i + 1].StartsWith("\t") || rawlisting[i + 1].StartsWith(" ")))
buf += rawlisting[++i];
item = FtpListItem.Parse(path, buf, m_caps); //重复了文件夹名称
// FtpListItem.Parse() returns null if the line
// could not be parsed
if (item != null && (item.Name != "." && item.Name != ".."))
lst.Add(item);
else
FtpTrace.WriteLine("Failed to parse file listing: " + buf);
}
// load extended information that wasn't available if the list options flags say to do so.
if (item != null) {
// try to dereference symbolic links if the appropriate list
// option was passed
if (item.Type == FtpFileSystemObjectType.Link && (options & FtpListOption.DerefLinks) == FtpListOption.DerefLinks) {
item.LinkObject = DereferenceLink(item);
}
if ((options & FtpListOption.Modify) == FtpListOption.Modify && HasFeature(FtpCapability.MDTM)) {
// if the modified date was not loaded or the modified date is more than a day in the future
// and the server supports the MDTM command, load the modified date.
// most servers do not support retrieving the modified date
// of a directory but we try any way.
if (item.Modified == DateTime.MinValue || listcmd.StartsWith("LIST")) {
DateTime modify;
if (item.Type == FtpFileSystemObjectType.Directory)
FtpTrace.WriteLine("Trying to retrieve modification time of a directory, some servers don't like this...");
if ((modify = GetModifiedTime(item.FullName)) != DateTime.MinValue)
item.Modified = modify;
}
}
if ((options & FtpListOption.Size) == FtpListOption.Size && HasFeature(FtpCapability.SIZE)) {
// if no size was parsed, the object is a file and the server
// supports the SIZE command, then load the file size
if (item.Size == -1) {
if (item.Type != FtpFileSystemObjectType.Directory) {
item.Size = GetFileSize(item.FullName);
}
else {
item.Size = 0;
}
}
}
}
}
return lst.ToArray();
}
/// <summary>
/// Creates a valid FTP path by appending the specified segments to this string
/// </summary>
/// <param name="path">This string</param>
/// <param name="segments">The path segments to append</param>
/// <returns>A valid FTP path</returns>
public static string GetFtpPath(this string path, params string[] segments) {
if (String.IsNullOrEmpty(path))
path = "./";
foreach (string part in segments) {
if (part != null) {
if (path.Length > 0 && !path.EndsWith("/"))
path += "/";
//path += Regex.Replace(part.Replace('\\', '/'), "[/]+", "/").TrimEnd('/'); //变成重复
}
}
path = Regex.Replace(path.Replace('\\', '/'), "[/]+", "/").TrimEnd('/');
if (path.Length == 0)
path = "/";
/*if (!path.StartsWith("/") || !path.StartsWith("./"))
path = "./" + path;*/
return path;
}
测试
/// <summary>
/// 涂聚文
/// Geovin Du
/// 2017-08-02
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void button1_Click(object sender, EventArgs e)
{
FtpClient client = new FtpClient();
client.Host = ftpServer;
client.Encoding = System.Text.Encoding.GetEncoding("GB2312");
// if you don't specify login credentials, we use the "anonymous" user account
client.Credentials = new NetworkCredential(user, pwd);
// begin connecting to the server
client.Connect();
//client.SetWorkingDirectory("/htdocs/");
//文件夹和文件(未成功)
//FtpListOption.NameList 当前文件夹下的文件
//FtpListOption.AllFiles 当前文件夹下文件和文件夹
FtpListItem[] items = client.GetListing("/htdocs/", FtpListOption.AllFiles);//根目录下可以。 AllFiles
this.dataGridView1.DataSource = items;
//获取的是所有文件名
//client.SetWorkingDirectory("/htdocs/");
//string[] items = client.GetNameListing();
//List<FileInfoList> list = new List<FileInfoList>();
//foreach (string str in items)
//{
// FileInfoList info = new FileInfoList();
// info.Name = str;
// info.Date = DateTime.Now;
// list.Add(info);
//}
//this.dataGridView1.DataSource = list;
}
}
/// <summary>
///
/// </summary>
public class FileInfoList
{
public string Name { set; get; }
public DateTime Date { set; get; }
}
https://github.com/hgupta9/FluentFTP
/// <summary>
/// Gets a file listing from the server. Each <see cref="FtpListItem"/> object returned
/// contains information about the file that was able to be retrieved.
/// 读取文件和文件夹
/// 涂聚文 2017-08-02 小小修改
/// </summary>
/// <remarks>
/// If a <see cref="DateTime"/> property is equal to <see cref="DateTime.MinValue"/> then it means the
/// date in question was not able to be retrieved. If the <see cref="FtpListItem.Size"/> property
/// is equal to 0, then it means the size of the object could also not
/// be retrieved.
/// </remarks>
/// <param name="path">The path of the directory to list</param>
/// <param name="options">Options that dictacte how a list is performed and what information is gathered.</param>
/// <returns>An array of FtpListItem objects</returns>
/// <example><code source="..\Examples\GetListing.cs" lang="cs" /></example>
public FtpListItem[] GetListing(string path, FtpListOption options) {
FtpTrace.WriteFunc("GetListing", new object[] { path, options });
FtpListItem item = null;
List<FtpListItem> lst = new List<FtpListItem>();
List<string> rawlisting = new List<string>();
string listcmd = null;
string buf = null;
// read flags
bool isIncludeSelf = (options & FtpListOption.IncludeSelfAndParent) == FtpListOption.IncludeSelfAndParent;
bool isForceList = (options & FtpListOption.ForceList) == FtpListOption.ForceList;
bool isNoPath = (options & FtpListOption.NoPath) == FtpListOption.NoPath;
bool isNameList = (options & FtpListOption.NameList) == FtpListOption.NameList;
bool isUseLS = (options & FtpListOption.UseLS) == FtpListOption.UseLS;
bool isAllFiles = (options & FtpListOption.AllFiles) == FtpListOption.AllFiles;
bool isRecursive = (options & FtpListOption.Recursive) == FtpListOption.Recursive && RecursiveList;
bool isDerefLinks = (options & FtpListOption.DerefLinks) == FtpListOption.DerefLinks;
bool isGetModified = (options & FtpListOption.Modify) == FtpListOption.Modify;
bool isGetSize = (options & FtpListOption.Size) == FtpListOption.Size;
// calc path to request
path = GetAbsolutePath(path);
// MLSD provides a machine readable format with 100% accurate information
// so always prefer MLSD over LIST unless the caller of this method overrides it with the ForceList option
bool machineList = false; //||
if ((!isForceList & m_parser == FtpParser.Machine) && HasFeature(FtpCapability.MLSD)) {
listcmd = "MLSD";
machineList = true;
} else {
if (isUseLS) {
listcmd = "LS";
} else if (isNameList) {
listcmd = "NLST";
} else {
string listopts = "";
listcmd = "LIST";
if (isAllFiles)
listopts += "a"; //读取所有文件夹和文件
if (isRecursive)
listopts += "R";
if (listopts.Length > 0)
listcmd += " -" + listopts;
}
}
if (!isNoPath) {
listcmd = (listcmd + " " + path.GetFtpPath());
}
#if !CORE14
lock (m_lock) {
#endif
Execute("TYPE I");
//读取出文件夹或文件 读取所有文件夹和文件 LIST a
// read in raw file listing
using (FtpDataStream stream = OpenDataStream(listcmd, 0)) {
try {
FtpTrace.WriteLine(FtpTraceLevel.Verbose, "+---------------------------------------+");
if (this.BulkListing) {
// increases performance of GetListing by reading multiple lines of the file listing at once
foreach (var line in stream.ReadAllLines(Encoding, this.BulkListingLength)) {
if (!FtpExtensions.IsNullOrWhiteSpace(line)) {
rawlisting.Add(line);
FtpTrace.WriteLine(FtpTraceLevel.Verbose, "Listing: " + line);
}
}
} else {
// GetListing will read file listings line-by-line (actually byte-by-byte)
while ((buf = stream.ReadLine(Encoding)) != null) {
if (buf.Length > 0) {
rawlisting.Add(buf);
FtpTrace.WriteLine(FtpTraceLevel.Verbose, "Listing: " + buf);
}
}
}
FtpTrace.WriteLine(FtpTraceLevel.Verbose, "-----------------------------------------");
} finally {
stream.Close();
}
}
#if !CORE14
}
#endif
//在上循环中读取文件或文件夹属性
for (int i = 0; i < rawlisting.Count; i++) {
buf = rawlisting[i];
if (isNameList) {
// if NLST was used we only have a file name so
// there is nothing to parse.
item = new FtpListItem() {
FullName = buf
};
if (DirectoryExists(item.FullName))
item.Type = FtpFileSystemObjectType.Directory;
else
item.Type = FtpFileSystemObjectType.File;
lst.Add(item);
} else {
// if this is a result of LIST -R then the path will be spit out
// before each block of objects
if (listcmd.StartsWith("LIST") && isRecursive) {
if (buf.StartsWith("/") && buf.EndsWith(":")) {
path = buf.TrimEnd(':');
continue;
}
}
// if the next line in the listing starts with spaces
// it is assumed to be a continuation of the current line
if (i + 1 < rawlisting.Count && (rawlisting[i + 1].StartsWith("\t") || rawlisting[i + 1].StartsWith(" ")))
buf += rawlisting[++i];
try {
item = m_listParser.ParseSingleLine(path, buf, m_caps, machineList);
} catch (FtpListParser.CriticalListParseException) {
FtpTrace.WriteStatus(FtpTraceLevel.Verbose, "Restarting parsing from first entry in list");
i = -1;
lst.Clear();
continue;
}
// FtpListItem.Parse() returns null if the line
// could not be parsed
if (item != null) {
if (isIncludeSelf || !(item.Name == "." || item.Name == "..")) {
lst.Add(item);
} else {
//FtpTrace.WriteStatus(FtpTraceLevel.Verbose, "Skipped self or parent item: " + item.Name);
}
} else {
FtpTrace.WriteStatus(FtpTraceLevel.Warn, "Failed to parse file listing: " + buf);
}
}
// load extended information that wasn't available if the list options flags say to do so.
if (item != null) {
// try to dereference symbolic links if the appropriate list
// option was passed
if (item.Type == FtpFileSystemObjectType.Link && isDerefLinks) {
item.LinkObject = DereferenceLink(item);
}
// if need to get file modified date
if (isGetModified && HasFeature(FtpCapability.MDTM)) {
// if the modified date was not loaded or the modified date is more than a day in the future
// and the server supports the MDTM command, load the modified date.
// most servers do not support retrieving the modified date
// of a directory but we try any way.
if (item.Modified == DateTime.MinValue || listcmd.StartsWith("LIST")) {
DateTime modify;
if (item.Type == FtpFileSystemObjectType.Directory)
FtpTrace.WriteStatus(FtpTraceLevel.Verbose, "Trying to retrieve modification time of a directory, some servers don't like this...");
if ((modify = GetModifiedTime(item.FullName)) != DateTime.MinValue)
item.Modified = modify;
}
}
// if need to get file size
if (isGetSize && HasFeature(FtpCapability.SIZE)) {
// if no size was parsed, the object is a file and the server
// supports the SIZE command, then load the file size
if (item.Size == -1) {
if (item.Type != FtpFileSystemObjectType.Directory) {
item.Size = GetFileSize(item.FullName); //尺寸要换算一下
} else {
item.Size = 0;
}
}
}
}
}
return lst.ToArray();
}
/// <summary>
/// Creates a valid FTP path by appending the specified segments to this string
/// 涂聚文 2017-08-02 小小修改
/// </summary>
/// <param name="path">This string</param>
/// <param name="segments">The path segments to append</param>
/// <returns>A valid FTP path</returns>
public static string GetFtpPath(this string path, params string[] segments) {
if (String.IsNullOrEmpty(path))
path = "./";
foreach (string part in segments) {
if (part != null) {
if (path.Length > 0 && !path.EndsWith("/"))
path += "/";
//path = Regex.Replace(part.Replace('\\', '/'), "[/]+", "/").TrimEnd('/'); //这里重复 path +=
}
}
path = Regex.Replace(path.Replace('\\', '/'), "[/]+", "/").TrimEnd('/');
if (path.Length == 0)
path = "/";
/*if (!path.StartsWith("/") || !path.StartsWith("./"))
path = "./" + path;*/
return path;
}