2010-01-14 14 views
6

ho scritto il seguente metodo per determinare la dimensione massima del file:ricorsione è la migliore opzione per la determinazione della massima dimensione del file in una directory

public static long GetMaxFileSize(string dirPath, long maxFileSize) 
    { 
     DirectoryInfo [] dirInfos = new DirectoryInfo(dirPath).GetDirectories(); 
     foreach (DirectoryInfo dirInfo in dirInfos) 
     { 
      DirectoryInfo [] subDirInfos = dirInfo.GetDirectories(); 
      foreach (DirectoryInfo subDirInfo in subDirInfos) 
       maxFileSize = GetMaxFileSize(dirInfo.FullName, maxFileSize); 

      FileInfo [] fileInfos = dirInfo.GetFiles(); 
      foreach (FileInfo fileInfo in fileInfos) 
      { 
       if (maxFileSize < fileInfo.Length) 
        maxFileSize = fileInfo.Length; 
      } 
     } 

     return maxFileSize; 
    } 

Code Complete raccomanda a "uso ricorsione in modo selettivo". Stando così le cose, mi chiedevo se la comunità pensava che questo fosse un uso valido della ricorsione. Se no, c'è una tecnica migliore per farlo?

EDIT: Non riesco a utilizzare LINQ perché non è disponibile in .NET 2.0, ma non voglio taggarlo come una domanda di .NET 2.0 solo per ulteriori punti di discussione come Jared di seguito.

MODIFICA: Codice pulito basato su un problema che non è stato rilevato nei file della directory radice.

public static long GetMaxFileSize(DirectoryInfo dirInfo, long maxFileSize) 
    { 
     DirectoryInfo [] subDirInfos = dirInfo.GetDirectories(); 
     foreach (DirectoryInfo subDirInfo in subDirInfos) 
     { 
      maxFileSize = GetMaxFileSize(subDirInfo, maxFileSize); 
     } 

     FileInfo [] fileInfos = dirInfo.GetFiles(); 
     foreach (FileInfo fileInfo in fileInfos) 
     { 
      if (maxFileSize < fileInfo.Length) 
       maxFileSize = fileInfo.Length; 
     } 

     return maxFileSize; 
    } 
+1

come si fa a gestire incroci e "scorciatoie" (hard link o simbolici)? Un albero di directory non è sempre un albero ... – lexu

+0

Non sono sicuro che sia * soggettivo *. Una volta stabilito cosa intendi per "migliore opzione" (impronta di memoria più veloce o più bassa o altro), qualsiasi soluzione specifica è facilmente verificabile. C'è un tag * oggettivo *? Per interesse - cosa intendevi per "migliore opzione"? –

+0

Non sapevo se avrei dovuto contrassegnarlo come soggettivo o no, ma lo rimuoverò a meno che qualcuno non oggetti. Con la migliore opzione intendevo la soluzione più elegante e affidabile. Non ero sicuro che esistesse una tecnica più sicura che potesse anche ridurre la quantità di codice richiesta. –

risposta

10

Penso che un modo migliore sia l'API del file system per eseguire la ricerca tramite Directory.GetFiles. Questo metodo fornisce la ricerca automatica delle sottodirectory. Questo elimina la domanda se ricorrere o meno e invece lascia la decisione su come implementarlo sul progettista dell'API (che probabilmente lo ha progettato per tale scenario).

Questo metodo combinato con LINQ fornisce una soluzione molto elegante

var max = Directory 
    .GetFiles(path, "*", SearchOption.AllDirectories) 
    .Select(x => new FileInfo(x)) 
    .Select(x => x.Length) 
    .Max(); 

EDIT Come Jimmy sottolineato, per 4.0 e superiore, è meglio usare EnumerateFiles per evitare il sovraccarico di creare un potenzialmente grande array

var max = Directory 
    .EnumerateFiles(path, "*", SearchOption.AllDirectories) 
    .Select(x => new FileInfo(x)) 
    .Select(x => x.Length) 
    .Max(); 
+0

Mi chiedevo se ci fosse qualcosa di simile. Sfortunatamente sono in .NET 2.0 e non ho questa opzione disponibile. Up-votato per coloro che utilizzano .NET 3.0 o versioni successive. –

+0

Questa è ovviamente una soluzione funzionale molto elegante, ma se le prestazioni sono una considerazione come questa tariffa? – ChaosPandion

+0

Immagino molto più veloce, dal momento che stai interrogando l'API del file system una volta. – Jimmy

4

Per quanto riguarda l'attraversamento dell'albero, ritengo che la ricorsione sia una misura fantastica. (La struttura della directory è un albero)

Finché si sa che la struttura della directory non è incredibilmente enorme, non ci si deve preoccupare di sovraccaricare lo stack.

soluzioni ricorsive per navigare alberi sono quasi sempre più elegante rispetto alle soluzioni iterative

+1

la struttura delle directory è spesso un albero, ma non deve essere, hard link (o soft link se li stanno seguendo) significa che si può visitare lo stesso file più di una volta, o addirittura avere un ciclo se il sistema operativo consente hard link alle directory –

0

ricorsione deve essere usato solo con determinate strutture di dati. Un file system, essendo una struttura ad albero, è sicuramente un buon caso per la ricorsione. Direi che questo è probabilmente il modo migliore per realizzare ciò che stai cercando di fare.

0

La raccomandazione sull'uso selettivo di "ricorsione" è attivata nelle dimensioni dello stack. Sui contenitori con numeri grandi, puoi far traboccare lo stack e causare il blocco del tuo codice.

Il problema che si presenterà sarà con directory di grandi dimensioni contenenti 65536 o più cartelle.

Ho riscontrato che Windows XP 32 bit si arresta in modo anomalo con chiamate di ricorsione a 64k.

1

Mi sembra perfettamente ragionevole: con un'eccezione, la profondità a cui discenderà il metodo è limitata dalla profondità del file system, che è garantito essere limitato.

L'eccezione è che se viene eseguito su un file system con collegamenti simbolici, si può seguire un collegamento a una directory che è un antenata di quella di partenza a, e quindi immettere un ciclo infinito, in modo da bisogno di prendere in considerazione

  • Sarà la vostra applicazione essere distribuiti su un tale file system (di solito Unix-like, ma penso che Vista e Win7 hanno il supporto)
  • vuoi ignorare i link simbolici
  • Fate la vostra desidera aggiungere un parametro aggiuntivo al metodo, che è un elenco di directory precedentemente inserite Ries.

Nell'implementazione tuttavia, si ignora costantemente i file nella directory corrente, quindi, dato un file-system

DirA 
| 
+-DirB 
| | 
| +- DirC 
| +- DirD 
| | | 
| | +-DirE 
| | 
| +- DirF 
| 
+- DirG 

e il percorso per DIRA, gli unici che ritenete sono DIRB, DirG e Dire

Hai bisogno di fare un GetFiles() nella directory corrente, quindi GetDirectories sulla directory corrente e ottenere le dimensioni di ciascuna di queste. Potrebbe avere senso che il metodo prenda un oggetto DirInfo per impostazione predefinita e lo sovraccarichi con un wrapper che prenda una stringa.

+0

Punto valido. Su ulteriore esame mi mancheranno i file delle directory radice. Lo cambierò di conseguenza. A proposito, come ignoreresti i link simbolici? I collegamenti simbolici –

+0

non devono essere troppo difficili, in quanto è possibile rilevare la differenza tra un collegamento simbolico e la cosa collegata, ma semplicemente non seguire i collegamenti simbolici. se il sistema operativo consente collegamenti hard casuali a dirs anche se si può essere in un mondo di dolore –

Problemi correlati