使用FTP和C#下载所有文件
使用C#和FTP下载远程目录中的所有文件并将其保存到本地目录的最佳方法是什么?
谢谢。
下载特定文件夹中的所有文件似乎是一项简单的任务。 但是,有一些问题需要解决。 仅举几例:
- 如何获取文件列表(System.Net.FtpWebRequest为您提供未解析的列表和目录列表格式在任何RFC中都未标准化)
- 如果远程目录同时包含文件和子目录,该怎么办? 我们是否必须深入了解子目录并下载它的内容?
- 如果本地计算机上已存在某些远程文件怎么办? 他们应该被覆盖吗? 跳过? 我们应该只覆盖旧文件吗?
- 如果本地文件不可写怎么办? 整个转移是否会失败? 我们应该跳过文件继续下一个吗?
- 如何处理远程磁盘上由于我们没有足够的访问权限而无法读取的文件?
- 如何处理符号链接 , 硬链接和连接点 ? 链接可以很容易地用于创建无限递归目录树结构 。 考虑带有子文件夹B的文件夹A,实际上它不是真正的文件夹,而是指向文件夹A的* nix硬链接。天真的方法将在一个永不停止的应用程序中结束(至少如果没有人设法拔掉插件)。
体面的第三方FTP组件应该有一个处理这些问题的方法。 以下代码使用我们的Rebex FTP for .NET 。
using (Ftp client = new Ftp()) { // connect and login to the FTP site client.Connect("mirror.aarnet.edu.au"); client.Login("anonymous", "my@password"); // download all files client.GetFiles( "/pub/fedora/linux/development/i386/os/EFI/*", "c:\\temp\\download", FtpBatchTransferOptions.Recursive, FtpActionOnExistingFiles.OverwriteAll ); client.Disconnect(); }
该代码取自我在blog.rebex.net上提供的博文。 博客文章还引用了一个示例,该示例显示了如何询问用户如何处理每个问题(例如,覆盖/覆盖旧/跳过/全部跳过)。
使用C#FtpWebRequest和FtpWebReponse,您可以使用以下递归(确保文件夹字符串以’\’结尾):
public void GetAllDirectoriesAndFiles(string getFolder, string putFolder) { List dirIitems = DirectoryListing(getFolder); foreach (var item in dirIitems) { if ( item.Contains('.') ) { GetFile(getFolder + item, putFolder + item); } else { var subDirPut = new DirectoryInfo(putFolder + "\\" + item); subDirPut.Create(); GetAllDirectoriesAndFiles(getFolder + item + "\\", subDirPut.FullName + "\\"); } } }
“item.Contains(’。’)”有点原始,但已经为我的目的而工作。 如果您需要方法示例,请发表评论:
GetFile(string getFileAndPath, string putFileAndPath)
要么
DirectoryListing(getFolder)
对于FTP协议,您可以使用.NET框架中的FtpWebRequest
类 。 虽然它没有任何明确支持递归文件操作(包括下载)。 你必须自己实现递归:
- 列出远程目录
- 迭代条目,下载文件并递归到子目录(再次列出它们等)
棘手的部分是识别子目录中的文件。 使用FtpWebRequest
以便携方式无法做到这一点。 遗憾的是, FtpWebRequest
不支持MLSD
命令,这是在FTP协议中检索具有文件属性的目录列表的唯一可移植方式。 另请参阅检查FTP服务器上的对象是文件还是目录 。
你的选择是:
- 对文件名执行操作,该文件名肯定会对文件失败并对目录成功(反之亦然)。 即你可以尝试下载“名称”。 如果成功,它是一个文件,如果失败,它就是一个目录。 但是当您有大量条目时,这可能会成为性能问题。
- 您可能很幸运,在您的特定情况下,您可以通过文件名告诉目录中的文件(即所有文件都有扩展名,而子目录没有)
- 您使用长目录列表(
LIST
命令=ListDirectoryDetails
方法)并尝试解析特定于服务器的列表。 许多FTP服务器使用* nix样式列表,您可以在条目的最开头通过d
标识目录。 但是许多服务器使用不同的格式。 以下示例使用此方法(假设为* nix格式)
void DownloadFtpDirectory(string url, NetworkCredential credentials, string localPath) { FtpWebRequest listRequest = (FtpWebRequest)WebRequest.Create(url); listRequest.UsePassive = true; listRequest.Method = WebRequestMethods.Ftp.ListDirectoryDetails; listRequest.Credentials = credentials; List lines = new List (); using (WebResponse listResponse = listRequest.GetResponse()) using (Stream listStream = listResponse.GetResponseStream()) using (StreamReader listReader = new StreamReader(listStream)) { while (!listReader.EndOfStream) { lines.Add(listReader.ReadLine()); } } foreach (string line in lines) { string[] tokens = line.Split(new[] { ' ' }, 9, StringSplitOptions.RemoveEmptyEntries); string name = tokens[8]; string permissions = tokens[0]; string localFilePath = Path.Combine(localPath, name); string fileUrl = url + name; if (permissions[0] == 'd') { Directory.CreateDirectory(localFilePath); DownloadFtpDirectory(fileUrl + "/", credentials, localFilePath); } else { FtpWebRequest downloadRequest = (FtpWebRequest)WebRequest.Create(fileUrl); downloadRequest.UsePassive = true; downloadRequest.UseBinary = true; downloadRequest.Method = WebRequestMethods.Ftp.DownloadFile; downloadRequest.Credentials = credentials; using (Stream ftpStream = downloadRequest.GetResponse().GetResponseStream()) using (Stream fileStream = File.Create(localFilePath)) { ftpStream.CopyTo(fileStream); } } } }
url
必须如下:
-
ftp://example.com/
或 -
ftp://example.com/path/
或者使用支持递归下载的第三方库。
例如,使用WinSCP .NET程序集 ,只需调用Session.GetFiles
即可下载整个目录:
// Setup session options SessionOptions sessionOptions = new SessionOptions { Protocol = Protocol.Ftp, HostName = "example.com", UserName = "user", Password = "mypassword", }; using (Session session = new Session()) { // Connect session.Open(sessionOptions); // Download files session.GetFiles("/home/user/*", @"d:\download\").Check(); }
在内部,如果服务器支持,WinSCP使用MLSD
命令。 如果没有,它使用LIST
命令并支持许多不同的列表格式。
(我是WinSCP的作者)
您可以使用支持FTP的System.Net.WebClient.DownloadFile()
。 MSDN详细信息在这里
您可以使用laedit.net中的FTPClient 。 它在Apache许可下并且易于使用。
它使用FtpWebRequest :
- 首先,您需要使用
WebRequestMethods.Ftp.ListDirectoryDetails
来获取文件夹的所有列表的详细信息 - 对于每个文件,您需要使用
WebRequestMethods.Ftp.DownloadFile
将其下载到本地文件夹