2010-03-21 12 views
45

Voglio trovare rapidamente la dimensione totale di qualsiasi cartella utilizzando python.molto rapidamente ottenere dimensioni totali della cartella

import os 
from os.path import join, getsize, isfile, isdir, splitext 
def GetFolderSize(path): 
    TotalSize = 0 
    for item in os.walk(path): 
     for file in item[2]: 
      try: 
       TotalSize = TotalSize + getsize(join(item[0], file)) 
      except: 
       print("error with file: " + join(item[0], file)) 
    return TotalSize 
print(float(GetFolderSize("C:\\")) /1024 /1024 /1024) 

Questo è il semplice script che ho scritto per ottenere la dimensione totale della cartella, ci sono voluti circa 60 secondi (+ -5 secondi). Usando il multiprocessing l'ho ridotto a 23 secondi su una macchina quad-core.

Utilizzo di Esplora file di Windows richiede solo ~ 3 secondi (clic destro-> proprietà per vedere di persona). Quindi c'è un modo più veloce di trovare la dimensione totale di una cartella vicina alla velocità che Windows può fare?

Windows 7, python 2.6 (Le ricerche ma la maggior parte delle volte le persone hanno utilizzato un metodo molto simile al mio) Grazie in anticipo.

+0

Il codice presentato non è valido.Potresti pubblicare un esempio completo e minimale che hai effettivamente eseguito? – bignose

+0

Siamo spiacenti, aveva solo la funzione precedente, il resto è modificato in. – user202459

+0

correlati: [Calcolo di una dimensione di directory usando Python?] (Http://stackoverflow.com/questions/1392413/calculating-a-directory-size- using-python) – jfs

risposta

71

Tu sei in svantaggio.

di Windows Explorer utilizza quasi certamente FindFirstFile/FindNextFile sia per attraversare la struttura di directory e informazioni sulle dimensioni raccogliere (attraverso lpFindFileData) in un solo passaggio, facendo ciò che è essenzialmente un unico chiamata di sistema per file.

Python purtroppo non è il tuo amico in questo caso.Così,

  1. os.walkprimi inviti os.listdir (che chiama internamente FindFirstFile/FindNextFile)
    • tutte le chiamate di sistema supplementari fatte da questo punto in poi non può che farti più lento rispetto a Windows Explorer
  2. os.walkquindi chiama isdir per ciascun file restituito da os.listdir (che chiama internamente GetFileAttributesEx - o, prima di Win2k, un GetFileAttributes + FindFirstFile combinata) per rideterminare se ricorsione o non
  3. os.walk e os.listdir eseguirà allocazione di memoria aggiuntiva, stringa e matrice operazioni, ecc per riempire il loro valore di ritorno
  4. si quindi chiamare getsize per ogni file restituito da os.walk (che nuovo chiamate GetFileAttributesEx)

Questo è 3 volte più chiamate di sistema per file di Windows Explorer, oltre a spese di allocazione e manipolazione della memoria.

è possibile utilizzare la soluzione di Anurag, o provare a chiamare FindFirstFile/FindNextFile direttamente e in modo ricorsivo (che dovrebbe essere paragonabile alla performance di un cygwin o altro win32 portdu -s some_directory.)

Fare riferimento alla os.py per l'attuazione del os.walk , posixmodule.c per l'attuazione del listdir e win32_stat (invocato da entrambi isdir e getsize.)

noti che Python os.walk non è ottimale su tutte le piattaforme (Windows e * nizi), fino a Python3.1 incluso. Su Windows e * nices os.walk potrebbe raggiungere l'attraversamento in un unico passaggio senza chiamare isdir dal momento che entrambi FindFirst/FindNext (Windows) e opendir/readdir (* nix) già tornare tipo di file via lpFindFileData->dwFileAttributes (Windows) e dirent::d_type (* nix).

Forse counterintuitively, sulla maggior parte delle configurazioni moderne (ad esempio Win7 e NTFS, e anche alcune implementazioni SMB) GetFileAttributesEx è due volte lento come FindFirstFile di un singolo file (forse anche più lento rispetto l'iterazione di una directory con FindNextFile.)

Aggiornamento: Python 3.5 include la nuova funzione PEP 471os.scandir() che risolve questo problema restituendo gli attributi del file insieme al nome file. Questa nuova funzione è utilizzata per accelerare il os.walk() integrato (su Windows e Linux). È possibile utilizzare lo scandir module on PyPI per ottenere questo comportamento per le versioni precedenti di Python, incluso 2.x.

+1

Il PEP menzionato la pagina contiene un esempio esattamente per questo scopo: https://www.python.org/dev/peps/pep-0471/#examples – Hossein

20

Se si desidera la stessa velocità di Explorer, perché non utilizzare lo script di Windows per accedere alla stessa funzionalità utilizzando pythoncom, ad es.

import win32com.client as com 

folderPath = r"D:\Software\Downloads" 
fso = com.Dispatch("Scripting.FileSystemObject") 
folder = fso.GetFolder(folderPath) 
MB = 1024 * 1024.0 
print("%.2f MB" % (folder.Size/MB)) 

Funzionerà stesso di explorer, si può leggere di più su Scripting Runtime a http://msdn.microsoft.com/en-us/library/bstcxhf7(VS.85).aspx.

+1

Funziona alla grande, davvero sorprendente. Ma solo la maggior parte del tempo. In una directory ('C: \ Downloads') con una dimensione di 37 GB e 7000 file, il metodo ottiene il risultato quasi istantaneamente. Il modo os.walk() ottiene il risultato in un paio di secondi (3 secondi) Ma ho alcuni problemi su altre directory come C: \ Windows, C: \ utenti ecc. Dove si dice che si è verificata un'eccezione. – user202459

+1

@freakazo, C: \ Windows ha funzionato sulla mia macchina, quale errore si ottiene? –

+1

Traceback (ultima chiamata ultima): File "Test.py", riga 7, in stampa "% .2f MB"% (folder.Size/MB) File "C: \ python26_32 \ lib \ site- pacchetti \ win32com client \ dynamic.py", la linea 501, in __getattr__ ret = self._oleobj_.Invoke \ (retEntry.dispid, 0, invoke_type, 1) pywintypes.com_error: (-2147352567, 'avvenuta eccezione.' , (0, Nessuna, Nessuna, Nessuna, 0, -2146828218), Nessuna) Premere un tasto qualsiasi per continuare. . . ### Un altro paio di test ha dimostrato che è folder.size a dare il problema. folder.name, ad esempio, funziona nella directory C: \ Windows – user202459

5

Ho confrontato le prestazioni del codice Python con un albero di directory 15k contenente 190k file e lo ho confrontato con il comando du(1) che presumibilmente funziona con la stessa velocità del sistema operativo. Il codice Python impiegava 3,3 secondi rispetto a du, che impiegava 0,8 secondi. Questo era su Linux.

Non sono sicuro che ci sia molto da spremere dal codice Python. Si noti anche che la prima esecuzione di du ha richiesto 45 secondi, il che era ovviamente prima che gli i-node rilevanti si trovassero nella cache dei blocchi; quindi questa performance dipende fortemente dal modo in cui il sistema gestisce il suo negozio. Non mi sorprenderebbe se una o entrambe:

  1. os.path.getsize è sub-ottimale su Windows
  2. di Windows memorizza nella cache il contenuto della directory dimensione una volta calcolate
+2

Sembra che sia effettivamente più lento su Windows, su Windows con un albero di directory 23K e file 175K ci sono voluti circa 60 secondi. Utilizzando l'equivalente du windows ci sono voluti 6 secondi per il completamento. Quindi sembra che Python sia 10 volte più lento su Windows che du e 4 volte più lento su Linux. Quindi sembra che 1. os.path.getsize/os.walk sia effettivamente sub-ottimale su windows 2. Windows sembra memorizzare nella cache il contenuto delle directory 3. Windows è ancora più lento di Linux – user202459

Problemi correlati