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

时间:2009-05-26 23:40:34

标签: c# ftp download

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

感谢。

5 个答案:

答案 0 :(得分:3)

下载特定文件夹中的所有文件似乎是一件容易的事。但是,有一些问题需要解决。仅举几例:

  • 如何获取文件列表(System.Net.FtpWebRequest为您提供未解析的列表和目录列表格式在任何RFC中都未标准化)
  • 如果远程目录同时包含文件和子目录,该怎么办?我们是否必须深入了解子目录并下载它的内容?
  • 如果本地计算机上已存在某些远程文件,该怎么办?他们应该被覆盖吗?跳过?我们应该只覆盖旧文件吗?
  • 如果本地文件不可写怎么办?整个转移是否会失败?我们应该跳过该文件并继续下一个吗?
  • 如何处理远程磁盘上由于我们没有足够的访问权限而无法读取的文件?
  • symlinkshard linksjunction points如何处理?链接可以轻松用于创建infinite recursive directory tree structure。考虑带有子文件夹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上提供的blogpost。该博客文章还引用了一个示例,该示例显示了如何询问用户如何处理每个问题(例如,覆盖/覆盖旧/跳过/全部跳过)。

答案 1 :(得分:2)

使用C#FtpWebRequest和FtpWebReponse,您可以使用以下递归(确保文件夹字符串终止于' \'):

    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 + "\\");
            }
        }
    }

&#34; item.Contains(&#39;。&#39;)&#34;有点原始,但为我的目的工作。如果您需要方法示例,请发表评论:

GetFile(string getFileAndPath, string putFileAndPath)

DirectoryListing(getFolder)

答案 2 :(得分:2)

对于FTP协议,您可以使用.NET框架中的FtpWebRequest class。虽然它没有任何明确支持递归文件操作(包括下载)。你必须自己实现递归:

  • 列出远程目录
  • 迭代条目,下载文件并递归到子目录(再次列出它们等)。

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

您的选择是:

  • 对文件名执行操作,该文件名对于文件肯定会失败并对目录成功(反之亦然)。即你可以尝试下载“名称”。如果成功,它是一个文件,如果失败,它就是一个目录。但是当你有大量的条目时,这可能会成为一个性能问题。
  • 您可能很幸运,在您的具体情况下,您可以通过文件名告诉目录中的文件(即所有文件都有扩展名,而子目录则没有)
  • 您使用长目录列表(LIST command = 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<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/
  • ftp://example.com/path/

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

例如,使用WinSCP .NET assembly,只需拨打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的作者)

答案 3 :(得分:1)

您可以使用FTPClient from laedit.net。它受Apache许可,易于使用。

使用FtpWebRequest

  • 首先,您需要使用WebRequestMethods.Ftp.ListDirectoryDetails来获取文件夹
  • 的所有列表的详细信息
  • 表示您需要使用WebRequestMethods.Ftp.DownloadFile将其下载到本地文件夹的每个文件

答案 4 :(得分:1)

您可以使用支持FTP的System.Net.WebClient.DownloadFile()MSDN Details here