Classe C # per analizzare WebRequestMethods.Ftp.ListDirectoryDetails Risposta FTP

Sto creando un servizio per monitorare le posizioni FTP per i nuovi aggiornamenti e richiede la capacità di analizzare la risposta restituita da una risposta FtpWebRequest utilizzando il metodo WebRequestMethods.Ftp.ListDirectoryDetails . Sarebbe abbastanza facile se tutte le risposte seguissero lo stesso formato, ma diversi software server FTP forniscono diversi formati di risposta.

Ad esempio si potrebbe restituire:

08-10-11 12:02PM  Version2 06-25-09 02:41PM 144700153 image34.gif 06-25-09 02:51PM 144700153 updates.txt 11-04-10 02:45PM 144700214 digger.tif 

E un altro server potrebbe restituire:

 d--x--x--x 2 ftp ftp 4096 Mar 07 2002 bin -rw-r--r-- 1 ftp ftp 659450 Jun 15 05:07 TEST.TXT -rw-r--r-- 1 ftp ftp 101786380 Sep 08 2008 TEST03-05.TXT drwxrwxr-x 2 ftp ftp 4096 May 06 12:24 dropoff 

E sono state osservate anche altre differenze quindi è probabile che ci siano un numero di sottili differenze che non ho ancora incontrato.

Qualcuno sa di una class C # completamente gestita (non richiede l’accesso a dll esterne su Windows) che gestisce queste situazioni senza problemi?

Ho solo bisogno di elencare il contenuto di una directory con i seguenti dettagli: Nome file / directory, ultimo timestamp aggiornato o creato, nome file / directory.

Grazie in anticipo per eventuali suggerimenti, Gavin

Per la prima lista (DOS / Windows) questo codice farà:

 FtpWebRequest request = (FtpWebRequest)WebRequest.Create("ftp://ftp.example.com/"); request.Credentials = new NetworkCredential("user", "password"); request.Method = WebRequestMethods.Ftp.ListDirectoryDetails; StreamReader reader = new StreamReader(request.GetResponse().GetResponseStream()); string pattern = @"^(\d+-\d+-\d+\s+\d+:\d+(?:AM|PM))\s+(|\d+)\s+(.+)$"; Regex regex = new Regex(pattern); IFormatProvider culture = CultureInfo.GetCultureInfo("en-us"); while (!reader.EndOfStream) { string line = reader.ReadLine(); Match match = regex.Match(line); DateTime modified = DateTime.ParseExact( match.Groups[1].Value, "MM-dd-yy hh:mmtt", culture, DateTimeStyles.None); long size = (match.Groups[2].Value != "") ? long.Parse(match.Groups[2].Value) : 0; string name = match.Groups[3].Value; Console.WriteLine( "{0,-16} size = {1,9} modified = {2}", name, size, modified.ToString("yyyy-MM-dd HH:mm")); } 

Otterrete:

 Version2 size = 0 modified = 2011-08-10 12:02 image34.gif size = 144700153 modified = 2009-06-25 14:41 updates.txt size = 144700153 modified = 2009-06-25 14:51 digger.tif size = 144700214 modified = 2010-11-04 14:45 

Per l’altro elenco (* nix), vedere la mia risposta alla riga Parsing FtpWebRequest ListDirectoryDetails .


Ma, in realtà, cercare di analizzare l’elenco restituito da ListDirectoryDetails non è la strada giusta da percorrere.

Si desidera utilizzare un client FTP che supporta il moderno comando MLSD che restituisce un elenco di directory in un formato leggibile dalla macchina specificato nella RFC 3659 . L’analisi del formato leggibile dall’uomo restituito dall’antico comando LIST (utilizzato internamente da FtpWebRequest per il metodo ListDirectoryDetails ) deve essere utilizzato come ultima opzione, quando si parla di server FTP obsoleti, che non supportano il comando MLSD (come Microsoft Server FTP IIS).


Ad esempio con l’ assembly WinSCP .NET , è ansible utilizzare i suoi metodi Session.ListDirectory o Session.EnumerateRemoteFiles .

Utilizzano internamente il comando MLSD , ma possono tornare al comando LIST e supportare dozzine di diversi formati di elenchi leggibili dall’uomo.

L’elenco restituito viene presentato come raccolta di istanze RemoteFileInfo con proprietà come:

  • Name
  • LastWriteTime (con fuso orario corretto)
  • Length
  • FilePermissions (analizzato in singoli diritti)
  • Group
  • Owner
  • IsDirectory
  • IsParentDirectory
  • IsThisDirectory

(Sono l’autore di WinSCP)


La maggior parte delle altre librerie di terze parti farà lo stesso. L’utilizzo della class FtpWebRequest non è affidabile per questo scopo. Sfortunatamente, non ci sono altri client FTP integrati nel framework .NET.

Sto affrontando lo stesso problema e ho creato una soluzione semplice (sebbene non molto robusta) usando un Regex per analizzare le informazioni rilevanti da ciascuna linea usando i gruppi di cattura:

 public static Regex FtpListDirectoryDetailsRegex = new Regex(@".*(?(Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec))\s*(?[0-9]*)\s*(?([0-9]|:)*)\s*(?.*)", RegexOptions.Compiled | RegexOptions.IgnoreCase); 

È quindi ansible estrarre i valori dai gruppi di acquisizione per:

  string ftpResponse = "-r--r--r-- 1 ftp ftp 0 Nov 19 11:08 aaa.txt"; Match match = FtpListDirectoryDetailsRegex.Match(ftpResponse); string month = match.Groups["month"].Value; string day = match.Groups["day"].Value; string yearTime = match.Groups["yearTime"].Value; string fileName = match.Groups["fileName"].Value; 

Alcune cose che non si notano sono:

  • questo funzionerà solo per le risposte delle directory con il formato descritto nella variabile ftpResponse sopra. Nel mio caso sono fortunato ad accedere ogni volta allo stesso server FTP e quindi è improbabile che cambi il formato di risposta.
  • la variabile yearTime può rappresentare yearTime l’anno o l’ora del timestamp del file. Sarà necessario analizzarlo manualmente cercando un’istanza dei due punti: carattere che indicherà che questo gruppo di acquisizione contiene un tempo anziché l’anno

Una soluzione che ho trovato è EdtFTPnet

EdtFTPnet sembra essere una soluzione piuttosto ricca di funzionalità che gestisce molte opzioni FTP diverse, quindi è l’ideale.

È la soluzione open source gratuita che ho utilizzato per http://www.ftp2rss.com (un piccolo strumento di cui avevo bisogno, ma che potrebbe essere utile anche agli altri).

Dai un’occhiata al client FTP di http://Ftp.dll .

Include un parser automatico per elenchi di directory per la maggior parte dei server FTP su piattaforms Windows, Unix e Netware.

Si prega di notare che questo è un prodotto commerciale che ho sviluppato.