Загрузка всех файлов с использованием FTP и C # - PullRequest
2 голосов
/ 27 мая 2009

Каков наилучший способ загрузки всех файлов в удаленном каталоге с использованием C # и FTP и сохранения их в локальном каталоге?

Спасибо.

Ответы [ 5 ]

3 голосов
/ 02 июня 2009

загрузка всех файлов в определенную папку кажется простой задачей. Однако есть некоторые проблемы, которые необходимо решить. Чтобы назвать несколько:

  • Как получить список файлов (System.Net.FtpWebRequest дает вам неразобранный список и формат списка каталогов не стандартизирован ни в одном RFC)
  • Что если в удаленном каталоге есть как файлы, так и подкаталоги. Нужно ли нам погружаться в подкаталоги и загружать его содержимое?
  • Что если некоторые из удаленных файлов уже существуют на локальном компьютере? Должны ли они быть перезаписаны? Пропущенные? Должны ли мы перезаписывать только старые файлы?
  • Что если локальный файл недоступен для записи? Если весь перевод потерпит неудачу? Должны ли мы пропустить файл и перейти к следующему?
  • Как обращаться с файлами на удаленном диске, которые невозможно прочитать, потому что у нас нет достаточных прав доступа?
  • Как обрабатываются символические ссылки , жесткие ссылки и точки соединения ? Ссылки могут легко использоваться для создания бесконечной рекурсивной структуры дерева каталогов . Рассмотрим папку A с подпапкой B, которая на самом деле является не реальной папкой, а жесткой ссылкой * nix, указывающей на папку A. Наивный подход закончится приложением, которое никогда не заканчивается (по крайней мере, если никто не сможет отключить).

Достойный сторонний FTP-компонент должен иметь метод для решения этих проблем. Следующий код использует наш Rebex FTP для .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. Блог-пост также ссылается на пример, который показывает, как спросить пользователя, как решать каждую проблему (например, перезаписать / перезаписать более старый / пропустить / пропустить все).

2 голосов
/ 19 мая 2016

Для протокола FTP вы можете использовать FtpWebRequest класс из .NET Framework. Хотя он не имеет явной поддержки рекурсивных операций с файлами (включая загрузки). Вы должны осуществить рекурсию самостоятельно:

  • Список удаленных каталогов
  • Повторяйте записи, загружая файлы и возвращаясь в подкаталоги (перечисляя их снова и т. Д.)

Сложная задача - определить файлы из подкаталогов. Нет способа сделать это портативным способом с FtpWebRequest. К сожалению, FtpWebRequest не поддерживает команду MLSD, которая является единственным переносимым способом получения списка каталогов с атрибутами файлов в протоколе FTP. См. Также Проверка, является ли объект на FTP-сервере файлом или каталогом .

Ваши варианты:

  • Выполните операцию с именем файла, которая наверняка не удастся для файла и удастся для каталогов (или наоборот). То есть Вы можете попробовать скачать «имя». Если это удается, это файл, если это не удается, это каталог. Но это может стать проблемой производительности, когда у вас есть большое количество записей.
  • Возможно, вам повезет, и в вашем конкретном случае вы можете отличить файл из каталога по имени файла (то есть все ваши файлы имеют расширение, а подкаталоги - нет)
  • Вы используете длинный список каталогов (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 должно быть как:


Или используйте стороннюю библиотеку, которая поддерживает рекурсивные загрузки.

Например, с сборкой 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)

2 голосов
/ 03 апреля 2012

Используя 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)
1 голос
/ 08 октября 2010

Вы можете использовать System.Net.WebClient.DownloadFile(), который поддерживает FTP. MSDN Подробности здесь

1 голос
/ 19 сентября 2010

Вы можете использовать FTPClient от laedit.net . Он под лицензией Apache и прост в использовании.

Используется FtpWebRequest :

  • сначала вам нужно использовать WebRequestMethods.Ftp.ListDirectoryDetails, чтобы получить подробную информацию обо всем списке папок
  • для каждого файла вам нужно использовать WebRequestMethods.Ftp.DownloadFile, чтобы загрузить его в локальную папку
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...