2010-03-21 9 views
45

Quiero encontrar rápidamente el tamaño total de cualquier carpeta usando python.obteniendo muy rápidamente el tamaño total de la carpeta

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) 

Esa es la simple script que escribí para obtener el tamaño total de la carpeta, se tardó alrededor de 60 segundos (+ -5 segundos). Al usar multiprocesamiento, lo reduje a 23 segundos en una máquina de cuatro núcleos.

Usando el explorador de archivos de Windows solo toma ~ 3 segundos (clic derecho-> propiedades para verlo). Entonces, ¿hay una manera más rápida de encontrar el tamaño total de una carpeta cerca de la velocidad que windows puede hacerlo?

Windows 7, python 2.6 (Realicé búsquedas pero la mayoría de las veces las personas usaban un método muy similar al mío) Gracias de antemano.

+0

El código presentado no es válido.¿Podría publicar un ejemplo completo y mínimo que realmente haya ejecutado? – bignose

+0

Disculpe, solo tenía la función antes, el resto está editado en. – user202459

+0

relacionado: [Cálculo de un tamaño de directorio usando Python?] (Http://stackoverflow.com/questions/1392413/calculating-a-directory-size- using-python) – jfs

Respuesta

71

Usted está en desventaja.

Explorador de Windows es casi seguro que utiliza FindFirstFile/FindNextFile a ambos atraviesan la estructura de directorios y información a cobro revertido (a través de lpFindFileData) en una sola pasada, haciendo lo que es esencialmente una sola llamada al sistema por archivo.

Python no es desafortunadamente su amigo en este caso.Por lo tanto,

  1. os.walkprimeras llamadas os.listdir (que llama internamente FindFirstFile/FindNextFile)
    • ninguna llamada de sistema adicionales hechas de este punto en adelante sólo se hará más lenta de Windows Explorer
  2. os.walkluego llama a isdir para cada archivo devuelto por os.listdir (que llama internamente GetFileAttributesEx - o, antes de Win2k, un GetFileAttributes + FindFirstFile combo) para volver a determinar si se debe o no recursivo
  3. os.walk y os.listdir llevará a cabo asignación de memoria adicional, cuerda y la matriz operaciones, etc., para llenar su valor de retorno
  4. que continuación, llamar getsize para cada archivo devuelto por os.walk (que nuevo llamadas GetFileAttributesEx)

Eso es 3 veces más llamadas al sistema por archivo que Windows Explorer, más asignación de memoria y gastos generales de manipulación.

También se puede usar la solución de Anurag, o tratar de llamar FindFirstFile/FindNextFile directamente y de forma recursiva (que debe ser comparable con el rendimiento de un cygwin u otro win32 portdu -s some_directory.)

Consulte os.py para la ejecución de os.walk , posixmodule.c para la ejecución de listdir y win32_stat (invocada por tanto isdir y getsize.)

Tenga en cuenta que Python os.walk no es óptimo en todas las plataformas (Windows y * nices), hasta e incluyendo Python3.1. En Windows y * nices os.walk podría alcanzar el recorrido de una sola pasada sin llamar isdir ya que ambos FindFirst/FindNext (Windows) y opendir/readdir (* nix) ya volver tipo de archivo a través de lpFindFileData->dwFileAttributes (Windows) y dirent::d_type (* nix).

Quizás counterintuitively, en la mayoría de las configuraciones modernas (por ejemplo, Win7 y NTFS, e incluso algunas implementaciones de SMB) GetFileAttributesEx es dos veces tan lento como FindFirstFile de un solo archivo (posiblemente incluso más lento que la iteración en un directorio con FindNextFile.)

Actualización: Python 3.5 incluye la nueva función PEP 471os.scandir() que resuelve este problema devolviendo los atributos del archivo junto con el nombre del archivo. Esta nueva función se usa para acelerar el os.walk() incorporado (tanto en Windows como en Linux). Puede usar el scandir module on PyPI para obtener este comportamiento para las versiones anteriores de Python, incluido 2.x.

+1

El mencionado PEP La página contiene un ejemplo para exactamente este propósito: https://www.python.org/dev/peps/pep-0471/#examples – Hossein

20

Si desea la misma velocidad que el explorador, ¿por qué no utilizar las secuencias de comandos de Windows para acceder a la misma funcionalidad mediante pythoncom, p.

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)) 

Funcionará igual que el explorador, puede leer más información sobre el tiempo de ejecución de secuencias de comandos en http://msdn.microsoft.com/en-us/library/bstcxhf7(VS.85).aspx.

+1

Eso funciona genial, realmente sorprendente. Pero solo la mayor parte del tiempo. En un directorio ('C: \ Descargas') con un tamaño de 37 GB y 7 000 archivos, su método obtiene el resultado casi instantáneamente. El camino os.walk() obtiene el resultado en un par de segundos (3 segundos) Pero tengo algunos problemas en otros directorios como C: \ Windows, C: \ users, etc. donde dice que se produjo una excepción. – user202459

+1

@freakazo, C: \ Windows funcionó en mi máquina, ¿qué error obtienes? –

+1

Traceback (última llamada más reciente): Archivo "Test.py", línea 7, en print "% .2f MB"% (carpeta.Tamaño/MB) Archivo "C: \ python26_32 \ lib \ site- packages \ win32com \ client \ dynamic.py ", línea 501, en __getattr__ ret = self._oleobj_.Invoke (retEntry.dispid, 0, invoke_type, 1) pywintypes.com_error: (-2147352567, 'Excepción producida'. , (0, Ninguno, Ninguno, Ninguno, 0, -2146828218), Ninguno) Presione cualquier tecla para continuar. . . ### Un par de pruebas más mostraron que es el tamaño de la carpeta el que está dando el problema. folder.name por ejemplo funciona en el directorio C: \ Windows – user202459

5

Comparé el rendimiento del código de Python con un árbol de directorios de 15k que contiene 190k archivos y lo comparé con el comando du(1) que presumiblemente funciona tan rápido como el sistema operativo. El código de Python tomó 3.3 segundos comparado con du que tomó 0.8 segundos. Esto fue en Linux.

No estoy seguro de que haya mucho que exprimir del código de Python. Tenga en cuenta también que la primera ejecución de du tomó 45 segundos, lo que obviamente fue antes de que los i-nodes relevantes estuvieran en la memoria caché del bloque; por lo tanto, este rendimiento depende en gran medida de cuán bien el sistema está administrando su tienda. No me sorprendería si una o ambas:

  1. os.path.getsize es sub-óptima en Windows
  2. de Windows almacena en caché el contenido del directorio Tamaño vez calculados
+2

Parece que de hecho es más lento en las ventanas, en las ventanas con un árbol de directorios de 23K y 175K archivos que tomó alrededor de 60 segundos. Usando el equivalente de du windows, tardó 6 segundos en completarse. Parece que Python es 10 veces más lento en Windows que en Ubuntu y 4 veces más lento en Linux. Parece que 1. os.path.getsize/os.walk no es óptimo en Windows 2. Windows parece almacenar en caché el contenido del directorio tamaño 3. Windows aún es más lento que Linux – user202459

Cuestiones relacionadas