簡體   English   中英

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

[英]Downloading all files using FTP and 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可用。 博客文章還引用了一個示例,該示例顯示了如何詢問用戶如何處理每個問題(例如,覆蓋/覆蓋舊/跳過/全部跳過)。

對於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<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程序集 ,只需調用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的作者)

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

“item.Contains('。')”有點原始,但已經為我的目的而工作。 如果您需要這些方法的示例,請發表評論:

GetFile(string getFileAndPath, string putFileAndPath)

要么

DirectoryListing(getFolder)

您可以使用laedit.net中的FTPClient 它在Apache許可下並且易於使用。

它使用FtpWebRequest

  • 首先,您需要使用WebRequestMethods.Ftp.ListDirectoryDetails來獲取文件夾的所有列表的詳細信息
  • 對於每個文件,您需要使用WebRequestMethods.Ftp.DownloadFile將其下載到本地文件夾

您可以使用支持FTP的System.Net.WebClient.DownloadFile() MSDN詳細信息在這里

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM