2009-05-26 14 views

Antwort

3

Das Herunterladen aller Dateien in einem bestimmten Ordner scheint eine einfache Aufgabe zu sein. Es gibt jedoch einige Probleme, die gelöst werden müssen. Ein paar zu nennen:

  • Wie man dorthin Liste von Dateien (System.Net.FtpWebRequest gibt Ihnen unparsed Liste und Verzeichnisliste Format wird nicht in allen RFC standardisiert)
  • Was passiert, wenn Remote-Verzeichnis hat beiden Dateien und Unterverzeichnisse . Müssen wir in die Untergebiete eintauchen und den Inhalt herunterladen?
  • Was passiert, wenn einige der Remote-Dateien bereits auf dem lokalen Computer vorhanden sind? Sollten sie überschrieben werden? Übersprungen? Sollten wir nur ältere Dateien überschreiben?
  • Was passiert, wenn die lokale Datei nicht beschreibbar ist? Sollte die gesamte Übertragung fehlschlagen? Sollten wir die Datei überspringen und mit der nächsten fortfahren?
  • Wie werden Dateien auf einem Remote-Datenträger behandelt, die nicht lesbar sind, weil wir nicht über ausreichende Zugriffsrechte verfügen?
  • Wie werden die symlinks, hard links und junction points behandelt? Links können leicht verwendet werden, um eine infinite recursive directory tree structure zu erstellen. Betrachten wir Ordner A mit Unterordner B, der eigentlich nicht der echte Ordner ist, sondern der harte Link * nix, der zurück zu Ordner A zeigt. Der naive Ansatz endet in einer Anwendung, die nie endet (zumindest wenn niemand den Stecker ziehen kann).

Ordentliche FTP-Komponente von Drittanbietern sollte eine Methode zur Behandlung dieser Probleme haben. Der folgende Code verwendet unsere 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", "[email protected]"); 

      // download all files 
      client.GetFiles(
       "/pub/fedora/linux/development/i386/os/EFI/*", 
       "c:\\temp\\download", 
       FtpBatchTransferOptions.Recursive, 
       FtpActionOnExistingFiles.OverwriteAll 
      ); 

      client.Disconnect(); 
     } 

Der Code wird bei blog.rebex.net von meinem blogpost verfügbar gemacht. Der Blogpost verweist auch auf ein Beispiel, das zeigt, wie der Benutzer gefragt wird, wie er mit jedem Problem umgehen soll (z. B. Überschreiben/Überschreiben älterer/Überspringen/Alle überspringen).

1

Sie können FTPClient from laedit.net verwenden. Es ist unter Apache-Lizenz und einfach zu bedienen.

Es verwenden FtpWebRequest:

  • zuerst müssen Sie WebRequestMethods.Ftp.ListDirectoryDetails verwenden, um das Detail der gesamten Liste des Ordners
  • für jede Dateien, die Sie WebRequestMethods.Ftp.DownloadFile verwenden müssen, um es in einen lokalen Ordner herunterladen
2

Verwendung von C# FtpWebRequest und FtpWebReponse, können Sie die folgende Rekursion verwenden (stellen Sie sicher, dass die Ordner Strings enden in '\'):

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

Die "item.contains ('')" ist ein bisschen primitiv, aber hat für meine Zwecke gearbeitet.Einen Kommentar abgeben, wenn Sie ein Beispiel für die Methoden benötigen:

GetFile(string getFileAndPath, string putFileAndPath) 

oder

DirectoryListing(getFolder) 
2

Für FTP-Protokoll Sie FtpWebRequest class von .NET Framework verwenden können. Es hat jedoch keine explizite Unterstützung für rekursive Dateioperationen (einschließlich Downloads). Sie haben die Rekursion selbst zu implementieren:

  • Liste der Remote-Verzeichnis
  • Iterate die Einträge, das Herunterladen von Dateien und rekursiv in Unterverzeichnissen (Auflistung sie wieder, usw.)

Tricky Teil zu identifizieren ist Dateien aus Unterverzeichnissen. Mit der FtpWebRequest ist das nicht möglich. Die FtpWebRequest unterstützt leider nicht den MLSD Befehl, der die einzige portable Möglichkeit ist, Verzeichnisliste mit Dateiattributen in FTP-Protokoll abzurufen. Siehe auch Checking if object on FTP server is file or directory.

Optionen sind verfügbar:

  • Sie eine Operation auf einen Dateinamen, die Datei scheitern und erfolgreich für Verzeichnisse (oder umgekehrt) ist sicher. I.e. Sie können versuchen, den "Namen" herunterzuladen. Wenn das gelingt, ist es eine Datei, wenn das fehlschlägt, ist es ein Verzeichnis. Aber das kann zu einem Leistungsproblem werden, wenn Sie eine große Anzahl von Einträgen haben.
  • können Sie Glück haben und in Ihrem speziellen Fall, können Sie eine Datei aus einem Verzeichnis durch einen Dateinamen (dh alle Dateien haben eine Erweiterung, während Unterverzeichnisse nicht) sagen
  • Sie verwenden eine lange Verzeichnisliste (LIST command = ListDirectoryDetails Methode) und versuchen, eine serverspezifische Auflistung zu analysieren. Viele FTP-Server verwenden eine * nix-style-Auflistung, in der Sie ein Verzeichnis durch die d am Anfang des Eintrags identifizieren. Viele Server verwenden jedoch ein anderes Format. Das folgende Beispiel verwendet diesen Ansatz (die * nix-Format vorausgesetzt) ​​
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); 
      } 
     } 
    } 
} 

Die url muss wie:

  • ftp://example.com/ oder
  • ftp://example.com/path/

Oder verwenden Sie eine Drittanbieterbibliothek, die rekursive Downloads unterstützt.

Zum Beispiel mit WinSCP .NET assembly können Sie ganzes Verzeichnis mit einem einzigen Aufruf Session.GetFiles herunterladen:

// 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(); 
} 

Intern WinSCP den MLSD Befehl verwendet, wenn vom Server unterstützt. Ist dies nicht der Fall, wird der Befehl LIST verwendet und Dutzende verschiedener Listenformate unterstützt.

(ich bin der Autor von WinSCP)

+1

Gerade über WinSCP für genau diesen Zweck, Dank im Voraus zum Download bereit. Ich hatte das Gefühl, dass mir das einige Zeit ersparen könnte. –