2015-04-22 18 views
8

Per il mio progetto WPF, devo calcolare la dimensione totale del file in una singola directory (che potrebbe avere sottodirectory).Perché EnumerateFiles è molto più veloce del calcolo delle dimensioni

Esempio 1

DirectoryInfo di = new DirectoryInfo(path); 
var totalLength = di.EnumerateFiles("*.*", SearchOption.AllDirectories).Sum(fi => fi.Length); 

if (totalLength/1000000 >= size) 
    return true; 

Esempio 2

var sizeOfHtmlDirectory = Directory.GetFiles(path, "*.*", SearchOption.AllDirectories); 
long totalLength = 0; 
foreach (var file in sizeOfHtmlDirectory) 
{ 
    totalLength += new FileInfo(file).Length; 
    if (totalLength/1000000 >= size) 
     return true; 
} 

Entrambi i campioni funzionano.

Esempio 1 completo in un tempo molto più veloce. Non l'ho cronometrato con precisione ma sul mio PC, usando la stessa cartella con lo stesso contenuto/dimensioni dei file, l'Esempio 1 richiede alcuni secondi, l'Esempio 2 richiede alcuni minuti.

EDIT

Tengo a precisare, il collo della bottiglia in Esempio 2 è all'interno del ciclo foreach! Legge rapidamente GetFiles ed entra rapidamente nel ciclo di foreach.

La mia domanda è, come faccio a scoprire perché questo è il caso?

+0

Potrebbe essere perché con 'GetFiles' è necessario prima enumerare tutti i file prima di restituire un singolo risultato. Prova ad aggiungere un 'ToArray()' prima di '.Sum' – xanatos

+0

E potresti anche provare' Directory.EnumerateFiles'/'DirectorInfo.GetFiles' – xanatos

+1

Hai anche confrontato con l'approccio che usi' DirectoryInfo' come root e 'dirInfo.GetFiles' per ottenere tutti gli oggetti' FileInfo'? –

risposta

8

Contrariamente a quanto le altre risposte indicano la differenza principale non è EnumerateFiles vs GetFiles - è DirectoryInfo vs Directory - in quest'ultimo caso si hanno solo le stringhe e devono creare nuove FileInfo casi separatamente, che è molto costoso.

DirectoryInfo rendimenti FileInfo le istanze che utilizzano informazioni memorizzate nella cache vs creare direttamente nuovi FileInfo casi che non fa - maggiori dettagli here e here.

quote rilevanti (tramite "The Old New Thing"):

In NTFS, metadati del file system è una proprietà non di voce di directory ma piuttosto del file, con alcuni dei metadati replicato in la voce di rubrica come tweak per migliorare la prestazione di enumerazione delle directory . Funzioni come FindFirstFile riportano la voce della directory e inserendo i metadati che gli utenti FAT erano abituati a ricevendo "gratuitamente", potevano evitare di essere più lenti di FAT per gli elenchi delle directory . Le funzioni di enumerazione delle directory riportano i metadati aggiornati all' , che potrebbero non corrispondere ai metadati effettivi se la voce della directory è obsoleta.

+1

Mentre avevo [lo stesso pensiero] (http://stackoverflow.com/questions/29800121/why-is-enumeratefiles-much-quicker-than-calculating-the-sizes/29800250#comment47728570_29800121), come fai a sapere che 'EnumerateFiles' non ha bisogno di fare lo stesso sotto il cofano? Anche le istanze 'FileInfo' devono essere inizializzate. Forse c'è un sovraccarico di IO se usi 'FileInfo (file) .Length' perché il file deve essere prima cercato. –

+0

Potrebbe essere che ... FileInfoResultHandler.CreateObject inizializza il FileInfo che deve essere restituito direttamente da un Win32Native.WIN32_FIND_DATA – xanatos

+0

@TimSchmelter alla fine, tutti finiscono per utilizzare lo stesso [FileSystemEnumerator] (http://referencesource.microsoft.com/ # mscorlib/system/io/filesystemenumerable.cs, e9aaa9fc3bf05462) classe. Pertanto, il collo di bottiglia molto probabilmente è il fatto che una chiamata extra a 'FileInfo' durante l'iterazione. – James

-1

EnumerateFiles è asincrono mentre GetFiles attende finché tutti i file sono stati enumerati prima di restituire la raccolta di file. Ciò avrà un grande effetto sul tuo risultato.

+1

No, non è questo il motivo perché OP vuole comunque elaborare tutti i file. –

Problemi correlati