2017-06-20 3 views
1

Ich arbeite an C# -Web-Anwendung und müssen Dateien mit FTP in den lokalen Ordner herunterladen. Für diese Bilder muss das Änderungsdatum größer als das von mir angegebene Datum sein.Herunterladen von Dateien vom FTP-Server in C# in lokalen Ordner mit Änderungsdatum größer als angegeben

Code:

public static List<FTPLineResult> GetFilesListSortedByDate(string ftpPath, Regex nameRegex, DateTime cutoff, System.Security.Cryptography.X509Certificates.X509Certificate cert) 
{ 
    List<FTPLineResult> output = new List<FTPLineResult>(); 

    if (cert != null) 
    { 
     FtpWebRequest request = FtpWebRequest.Create(ftpPath) as FtpWebRequest; 
     request.Credentials = new NetworkCredential("unm", "pwd"); 
     request.ClientCertificates.Add(cert); 

     ConfigureProxy(request); 
     request.Method = WebRequestMethods.Ftp.ListDirectoryDetails; 
     FtpWebResponse response = request.GetResponse() as FtpWebResponse; 
     StreamReader directoryReader = new StreamReader(response.GetResponseStream(), System.Text.Encoding.ASCII); 
     var parser = new FTPLineParser(); 
     while (!directoryReader.EndOfStream) 
     { 
      var result = parser.Parse(directoryReader.ReadLine()); 
      if (!result.IsDirectory && result.DateTime > cutoff && nameRegex.IsMatch(result.Name)) 
      { 
       output.Add(result); 
      } 
     } 
     // need to ensure the files are sorted in ascending date order 
     output.Sort(
      new Comparison<FTPLineResult>(
       delegate(FTPLineResult res1, FTPLineResult res2) 
       { 
        return res1.DateTime.CompareTo(res2.DateTime); 
       } 
      ) 
     ); 
    } 

    return output; 
} 

Ich habe Zertifikat verwenden (P12).
Wie kann ich das tun?

Antwort

2

Sie müssen Zeitstempel von Remote-Dateien abrufen, um die gewünschten auszuwählen.

Leider gibt es keine wirklich zuverlässige und effiziente Methode zum Abrufen von Zeitstempeln mit den von .NET Framework angebotenen Funktionen, da FTP MLSD nicht unterstützt wird. Der Befehl MLSD bietet die Auflistung des entfernten Verzeichnisses in einem standardisierten maschinenlesbaren Format. Der Befehl und das Format sind durch die RFC 3659 standardisiert.

Alternativen Sie verwenden können, die von .NET Framework unterstützt:

  • die ListDirectoryDetails method (FTP LIST Befehl) Details aller Dateien in einem Verzeichnis abrufen und dann geht man mit FTP-Server bestimmten Format der Details

    * nix-Format: Parsing FtpWebRequest ListDirectoryDetails line DOS/Windows-Format: C# class to parse WebRequestMethods.Ftp.ListDirectoryDetails FTP response

  • die GetDateTimestamp method (FTP MDTM Befehl) zum individuellen Abrufen von Zeitstempeln für jede Datei. Vorteil ist, dass die Antwort von RFC 3659 auf YYYYMMDDHHMMSS[.sss] standardisiert ist. Nachteil ist, dass Sie für jede Datei eine separate Anfrage senden müssen, was sehr ineffizient sein kann.

    const string uri = "ftp://example.com/remote/path/file.txt"; 
    FtpWebRequest request = (FtpWebRequest)WebRequest.Create(uri); 
    request.Method = WebRequestMethods.Ftp.GetDateTimestamp; 
    FtpWebResponse response = (FtpWebResponse)request.GetResponse(); 
    Console.WriteLine("{0} {1}", uri, response.LastModified); 
    

Alternativ können Sie 3rd-Party-FTP-Client-Implementierung verwenden, die den modernen MLSD Befehl oder dass Dateien direkt herunterladen Constraint zeit unterstützt.

Zum Beispiel unterstützt WinSCP .NET assembly sowohl MLSD als auch time constraints.

Es gibt sogar ein Beispiel für Ihre spezifische Aufgabe: How do I transfer new/modified files only?
Das Beispiel für Powershell ist, aber übersetzt C# leicht:

// Setup session options 
SessionOptions sessionOptions = new SessionOptions 
{ 
    Protocol = Protocol.Ftp, 
    HostName = "ftp.example.com", 
    UserName = "username", 
    Password = "password", 
}; 

using (Session session = new Session()) 
{ 
    // Connect 
    session.Open(sessionOptions); 

    // Download files created in 2017-06-15 and later 
    TransferOptions transferOptions = new TransferOptions(); 
    transferOptions.FileMask = "*>=2017-06-15"; 
    session.GetFiles("/remote/path/*", @"C:\local\path\", false, transferOptions).Check(); 
} 

Obwohl für Web-Anwendung, WinSCP ist wahrscheinlich nicht die beste Lösung . Sie können möglicherweise eine andere 3rd-Party-Bibliothek mit ähnlicher Funktionalität finden.


WinSCP unterstützt auch die Authentifizierung mit einem Clientzertifikat. Siehe SessionOptions.TlsClientCertificatePath. Aber das ist wirklich für eine separate Frage.

(ich bin der Autor von WinSCP)

+0

Danke Martin, ich aktualisiert meinen Beitrag mit Code, den ich verwendet Liste der Dateien abzurufen. Kann ich Dateien während blockweise herunterladen, anstatt ** output.Add (result); ** kann ich etwas wie ** download (destnationfilename, sourcefilename) ** tun? – dragy

+0

Sicher kannst du. Aber ich denke nicht, dass es in Bezug auf die Performance viel helfen würde, wenn Sie das erwarten. –

+0

Ich dachte, ich könnte Datei im gleichen Durchlauf durch die While-Schleife herunterladen. In diesem Fall wäre es nicht notwendig, durch die gefilterte Liste zu gehen. Aber, ich wusste nicht, wie man Datei in existierender While-Schleife herunterlädt und tat es mit einer anderen passing thru erzeugten Liste. – dragy

Verwandte Themen