首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >使用FTP和C#下载所有文件

问使用FTP和C#下载所有文件
EN

Stack Overflow用户
提问于 2009-05-26 23:40:34
回答 5查看 19.9K关注 0票数 2

使用C#和FTP下载远程目录中的所有文件并将其保存到本地目录的最佳方法是什么?

谢谢。

EN

回答 5

Stack Overflow用户

发布于 2009-06-02 16:39:20

下载特定文件夹中的所有文件似乎是一项简单的任务。然而,还有一些问题需要解决。举几个例子:

  • 如何获取文件列表(System.Net.FtpWebRequest提供的是未解析的列表,目录列表格式在任何RFC中都不是标准化的)
  • 如果远程目录同时包含文件和子目录怎么办。我们是否必须深入到子目录并下载它的内容?
  • 如果本地计算机上已经存在一些远程文件怎么办?它们应该被覆盖吗?跳过?我们应该只覆盖旧文件吗?
  • 如果本地文件不可写怎么办?整个传输应该失败吗?我们应该跳过这个文件并继续下一个文件吗?
  • 如何处理远程磁盘上由于我们没有足够的访问权限而无法读取的文件?
  • 如何处理symlinks、hard links和junction points?可以很容易地使用链接来创建infinite recursive directory tree structure。考虑包含子文件夹B的文件夹A,它实际上不是真正的文件夹,而是指向文件夹A的*nix硬链接。这种天真的方法将以一个永远不会结束的应用程序而结束(至少在没有人设法拔出插头的情况下)。

像样的第三方FTP组件应该有一个方法来处理这些问题。下面的代码使用我们的Rebex FTP for .NET。

代码语言:javascript
复制
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上的blogpost。这篇博文还引用了一个示例,展示了如何询问用户如何处理每个问题(例如,覆盖/覆盖旧问题/跳过/跳过所有问题)。

票数 3
EN

Stack Overflow用户

发布于 2012-04-03 21:46:35

使用C# FtpWebRequest和FtpWebReponse,您可以使用以下递归(确保文件夹字符串以‘\’结尾):

代码语言:javascript
复制
    public void GetAllDirectoriesAndFiles(string getFolder, string putFolder)
    {
        List<string> 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(‘.)”有点原始,但已经达到了我的目的。如果您需要这些方法的示例,请发表评论:

代码语言:javascript
复制
GetFile(string getFileAndPath, string putFileAndPath)

或

代码语言:javascript
复制
DirectoryListing(getFolder)
票数 2
EN

Stack Overflow用户

发布于 2016-05-19 19:54:28

对于FTP协议,您可以使用.NET框架中的FtpWebRequest class。尽管它不支持任何显式的递归文件操作(包括下载)。您必须自己实现递归:

列出remote directory

  • Iterate
  • 条目,下载文件并递归到子目录(再次列出它们等)

棘手的部分是从子目录中识别文件。在FtpWebRequest中,无法以可移植的方式做到这一点。遗憾的是,FTP不支持MLSD命令,该命令是在FtpWebRequest协议中检索带有文件属性的目录列表的唯一可移植方法。另请参见Checking if object on FTP server is file or directory。

您可以选择:

  • 对文件名执行的操作对于文件肯定会失败,而对于目录肯定会成功(反之亦然)。也就是说,您可以尝试下载“名称”。如果成功,它就是一个文件,如果失败,它就是一个目录。
  • 你可能很幸运,在你的特殊情况下,你可以通过文件名来区分文件和目录(即你所有的文件都有扩展名,而子目录没有)
  • 你使用一个长的目录列表(LIST
  • = ListDirectoryDetails方法),并尝试解析特定于服务器的列表。许多FTP服务器使用*nix样式的列表,在这种列表中,您通过条目开头的d来标识目录。但许多服务器使用不同的格式。以下示例使用此方法(假设格式为*nix )

代码语言:javascript
复制
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<string> lines = new List<string>();

    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/ or
  • ftp://example.com/path/

或者使用支持递归下载的第三方库。

例如,使用WinSCP .NET assembly,只需调用一次Session.GetFiles即可下载整个目录

代码语言:javascript
复制
// 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的作者)

票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/913312

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档