https://netftp.codeplex.com/
class="brush:csharp;gutter:true;"> /// <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; }