Domanda

Ho bisogno di aiuto per analizzare la risposta da ListDirectoryDetails in C #.

Ho solo bisogno dei seguenti campi.

  • Nome file / Nome directory
  • Data di creazione
  • e la dimensione del file.

Ecco come appaiono alcune delle linee quando eseguo ListDirectoryDetails :

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

Grazie in anticipo.

È stato utile?

Soluzione

Non sono sicuro che tu abbia ancora bisogno di questo, ma questa è la soluzione che mi è venuta in mente:

Regex regex = new Regex ( @"^([d-])([rwxt-]{3}){3}\s+\d{1,}\s+.*?(\d{1,})\s+(\w+\s+\d{1,2}\s+(?:\d{4})?)(\d{1,2}:\d{2})?\s+(.+?)\s?<*>quot;,
    RegexOptions.Compiled | RegexOptions.Multiline | RegexOptions.IgnoreCase | RegexOptions.IgnorePatternWhitespace );

Gruppi di corrispondenza:

  1. tipo di oggetto:
    • d: directory
    • -: file
  2. Matrice [3] di autorizzazioni (rwx-)
  3. Dimensione file
  4. Data ultima modifica
  5. Ora ultima modifica
  6. Nome file / directory

Altri suggerimenti

Per questo elenco specifico, farà il seguente codice:

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 =
    @"^([\w-]+)\s+(\d+)\s+(\w+)\s+(\w+)\s+(\d+)\s+" +
    @"(\w+\s+\d+\s+\d+|\w+\s+\d+\s+\d+:\d+)\s+(.+)
bin              permissions = d--x--x--x  size =      4096  modified = 2002-03-07 00:00
TEST.TXT         permissions = -rw-r--r--  size =    659450  modified = 2016-06-15 05:07
TEST03-05.TXT    permissions = -rw-r--r--  size = 101786380  modified = 2008-09-08 00:00
dropoff          permissions = drwxrwxr-x  size =      4096  modified = 2016-05-06 12:24
quot;; Regex regex = new Regex(pattern); IFormatProvider culture = CultureInfo.GetCultureInfo("en-us"); string[] hourMinFormats = new[] { "MMM dd HH:mm", "MMM dd H:mm", "MMM d HH:mm", "MMM d H:mm" }; string[] yearFormats = new[] { "MMM dd yyyy", "MMM d yyyy" }; while (!reader.EndOfStream) { string line = reader.ReadLine(); Match match = regex.Match(line); string permissions = match.Groups[1].Value; int inode = int.Parse(match.Groups[2].Value, culture); string owner = match.Groups[3].Value; string group = match.Groups[4].Value; long size = long.Parse(match.Groups[5].Value, culture); DateTime modified; string s = Regex.Replace(match.Groups[6].Value, @"\s+", " "); if (s.IndexOf(':') >= 0) { modified = DateTime.ParseExact(s, hourMinFormats, culture, DateTimeStyles.None); } else { modified = DateTime.ParseExact(s, yearFormats, culture, DateTimeStyles.None); } string name = match.Groups[7].Value; Console.WriteLine( "{0,-16} permissions = {1} size = {2, 9} modified = {3}", name, permissions, size, modified.ToString("yyyy-MM-dd HH:mm")); }

Riceverai (a partire dall'anno 2016):

<*>

Ma, in realtà, provare ad analizzare l'elenco restituito da ListDirectoryDetails non è la strada giusta da percorrere.

Si desidera utilizzare un client FTP che supporti il ??moderno comando MLSD che restituisce un elenco di directory in un formato leggibile dalla macchina specificato in RFC 3659 . L'analisi del formato leggibile dall'uomo restituito dall'antico comando LIST (utilizzato internamente dal FtpWebRequest per il suo metodo ListDirectoryDetails ) dovrebbe essere utilizzato come ultimo opzione resort, quando si parla con server FTP obsoleti, che non supportano il comando MLSD (come il server FTP Microsoft IIS).

Molti server utilizzano un formato diverso per la risposta del comando LIST . In particolare IIS può utilizzare il formato DOS. Vedi Classe C # per analizzare WebRequestMethods.Ftp.ListDirectoryDetails Risposta FTP .


Ad esempio con WinSCP .NET assembly , puoi usare il suo Session.ListDirectory o Session.EnumerateRemoteFiles metodi.

Usano internamente il comando MLSD , ma possono ricorrere al comando LIST e supportare dozzine di diversi formati di elenchi leggibili dall'uomo.

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

  • Nome
  • LastWriteTime (con fuso orario corretto)
  • Lunghezza
  • FilePermissions (analizzato in diritti individuali)
  • gruppo
  • proprietario
  • isDirectory
  • IsParentDirectory
  • IsThisDirectory

(sono l'autore di WinSCP)


La maggior parte delle altre librerie di terze parti farà lo stesso. Utilizzo della FtpWebRequest class non è affidabile per questo scopo. Sfortunatamente, non esiste nessun altro client FTP integrato nel framework .NET.

Questo è il mio algoritmo per ottenere il nome del file / directory, la data di creazione, l'attributo (file / cartella), le dimensioni. Spero che questo aiuti ...

        FtpWebRequest _fwr = FtpWebRequest.Create(uri) as FtpWebRequest     
        _fwr.Credentials = cred;
        _fwr.UseBinary = true;
        _fwr.UsePassive = true;
        _fwr.KeepAlive = true;
        _fwr.Method = WebRequestMethods.Ftp.ListDirectoryDetails;
        StreamReader _sr = new StreamReader(_fwr.GetResponse().GetResponseStream());

        List<object> _dirlist = new List<object>();
        List<object> _attlist = new List<object>();
        List<object> _datelist = new List<object>();
        List<long> _szlist = new List<long>();
        while (!_sr.EndOfStream)
        {
            string[] buf = _sr.ReadLine().Split(' ');
            //string Att, Dir;
            int numcnt = 0, offset = 4; ;
            long sz = 0;
            for (int i = 0; i < buf.Length; i++)
            {
                //Count the number value markers, first before the ftp markers and second
                //the file size.
                if (long.TryParse(buf[i], out sz)) numcnt++;
                if (numcnt == 2)
                {
                    //Get the attribute
                    string cbuf = "", dbuf = "", abuf = "";
                    if (buf[0][0] == 'd') abuf = "Dir"; else abuf = "File";
                    //Get the Date
                    if (!buf[i+3].Contains(':')) offset++;
                    for (int j = i + 1; j < i + offset; j++)
                    {
                        dbuf += buf[j];
                        if (j < buf.Length - 1) dbuf += " ";
                    }
                    //Get the File/Dir name
                    for (int j = i + offset; j < buf.Length; j++)
                    {
                        cbuf += buf[j];
                        if (j < buf.Length - 1) cbuf += " ";
                    }
                    //Store to a list.
                    _dirlist.Add(cbuf);
                    _attlist.Add(abuf);
                    _datelist.Add(dbuf);
                    _szlist.Add(sz);

                    offset = 0;
                    break;
                }
            }
        }

Partendo dall'idea regex di Ryan Conrad , questo è il mio codice di lettura finale:

protected static Regex m_FtpListingRegex = new Regex(@"^([d-])((?:[rwxt-]{3}){3})\s+(\d{1,})\s+(\w+)?\s+(\w+)?\s+(\d{1,})\s+(\w+)\s+(\d{1,2})\s+(\d{4})?(\d{1,2}:\d{2})?\s+(.+?)\s?
public class FtpFileInfo
{
    public Boolean IsDirectory { get; set; }
    public Char[] Permissions { get; set; }
    public Int32 NrOfInodes { get; set; }
    public String User { get; set; }
    public String Group { get; set; }
    public Int64 FileSize { get; set; }
    public DateTime LastModifiedDate { get; set; }
    public String FileName { get; set; }
}
quot;, RegexOptions.Compiled | RegexOptions.Multiline | RegexOptions.IgnoreCase | RegexOptions.IgnorePatternWhitespace); protected static readonly String Timeformat = "MMM dd yyyy HH:mm"; /// <summary> /// Handles file info given in the form of a string in standard unix ls output format. /// </summary> /// <param name="filesListing">The file listing string.</param> /// <returns>A list of FtpFileInfo objects</returns> public static List<FtpFileInfo> GetFilesListFromFtpListingUnix(String filesListing) { List<FtpFileInfo> files = new List<FtpFileInfo>(); MatchCollection matches = m_FtpListingRegex.Matches(filesListing); if (matches.Count == 0 && filesListing.Trim('\r','\n','\t',' ').Length != 0) return null; // parse error. Could throw some kind of exception here too. foreach (Match match in matches) { FtpFileInfo fileInfo = new FtpFileInfo(); Char dirchar = match.Groups[1].Value.ToLowerInvariant()[0]; fileInfo.IsDirectory = dirchar == 'd'; fileInfo.Permissions = match.Groups[2].Value.ToCharArray(); // No clue what "inodes" actually means... Int32 inodes; fileInfo.NrOfInodes = Int32.TryParse(match.Groups[3].Value, out inodes) ? inodes : 1; fileInfo.User = match.Groups[4].Success ? match.Groups[4].Value : null; fileInfo.Group = match.Groups[5].Success ? match.Groups[5].Value : null; Int64 fileSize; Int64.TryParse(match.Groups[6].Value, out fileSize); fileInfo.FileSize = fileSize; String month = match.Groups[7].Value; String day = match.Groups[8].Value.PadLeft(2, '0'); String year = match.Groups[9].Success ? match.Groups[9].Value : DateTime.Now.Year.ToString(CultureInfo.InvariantCulture); String time = match.Groups[10].Success ? match.Groups[10].Value.PadLeft(5, '0') : "00:00"; String timeString = month + " " + day + " " + year + " " + time; DateTime lastModifiedDate; if (!DateTime.TryParseExact(timeString, Timeformat, CultureInfo.InvariantCulture, DateTimeStyles.None, out lastModifiedDate)) lastModifiedDate = DateTime.MinValue; fileInfo.LastModifiedDate = lastModifiedDate; fileInfo.FileName = match.Groups[11].Value; files.Add(fileInfo); } return files; }

E la classe FtpFileInfo che è piena:

<*>
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top