bardzo szybkie uzyskanie całkowitego rozmiaru folderu

Chcę szybko znaleźć całkowity rozmiar dowolnego folderu za pomocą Pythona.

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)

To prosty skrypt, który napisałem, aby uzyskać całkowity rozmiar folderu, zajęło to około 60 sekund (+-5 sekund). Korzystając z multiprocessingu, zmniejszyłem go do 23 sekund na czterordzeniowej maszynie.

Korzystanie z Eksploratora plików Windows zajmuje tylko ~3 sekundy (kliknij prawym przyciskiem myszy-> Właściwości, aby zobaczyć na własne oczy). Czy istnieje szybszy sposób na znalezienie całkowitego rozmiaru folderu zbliżonego do prędkości, jaką może zrobić System windows to?

Windows 7, python 2.6 (szukałem, ale większość czasu ludzie używali bardzo podobnej metody do mojego) Z góry dzięki.

Author: user202459, 2010-03-21

3 answers

Jesteś w niekorzystnej sytuacji.

Windows Explorer prawie na pewno używa FindFirstFile/FindNextFile Aby zarówno przejść strukturę katalogów i zebrać informacje o rozmiarze (przez lpFindFileData) W Jednym przejściu, co jest zasadniczo jednym wywołaniem systemowym na plik.

Python niestety nie jest twoim przyjacielem w tym przypadku. Tak więc

  1. os.walk pierwsze połączenia os.listdir (które wywołują FindFirstFile / FindNextFile)
    • wszelkie dodatkowe wywołania systemowe wykonywane od tego momentu mogą tylko spowolnić niż Eksplorator Windows
  2. os.walk następnie dzwoni isdir dla każdego pliku zwracanego przez os.listdir (który wewnętrznie wywołuje GetFileAttributesEx -- lub, przed Win2k, a GetFileAttributes+FindFirstFile combo), aby ponownie określić, czy rekurencyjnie, czy nie
  3. os.walk i os.listdir wykonają dodatkową alokację pamięci , operacje na łańcuchach i tablicach itp. aby wypełnić wartość zwracaną
  4. you then call getsize dla każdego pliku zwracanego przez os.walk (który ponownie wywołuje GetFileAttributesEx)

To 3x więcej wywołań systemowych na plik niż Windows Explorer, plus alokacja pamięci i manipulacja narzutu.

Możesz użyć rozwiązania Anurag, lub spróbować zadzwonić FindFirstFile/FindNextFile bezpośrednio i rekurencyjnie (co powinno być porównywalne do wydajności cygwin lub inny Port win32 du -s some_directory.)

Zobacz os.py na realizacja os.walk, posixmodule.c do realizacji listdir i win32_stat (zarówno isdir, jak i getsize.)

Zauważ, że Python jest os.walk jest nieoptymalna na wszystkich platformach (Windows i *nices), do Python3.1 włącznie. W obu oknach i * nices os.walk może osiągnąć Przejście W Jednym przejściu bez wywołania isdir, ponieważ oba FindFirst/FindNext (okna) oraz opendir/readdir (*nix) zwraca już typ pliku poprzez lpFindFileData->dwFileAttributes (Windows) i dirent::d_type (*nix).

Win7 i NTFS, a nawet niektóre implementacje SMB) GetFileAttributesEx jest dwa razy tak wolny jak FindFirstFile pojedynczego pliku (prawdopodobnie nawet wolniejszy niż iteracja nad katalogiem z FindNextFile.)

Aktualizacja: Python 3.5 zawiera nowy PEP 471 os.scandir() funkcja, która rozwiązuje ten problem zwracając atrybuty pliku wraz z nazwą pliku. Ta nowa funkcja służy do przyspieszenia wbudowanego os.walk() (zarówno Windows jak i Linux). Możesz użyć modułu scandir na PyPI , Aby uzyskać to zachowanie dla starszych wersji Pythona, w tym 2.x.

 73
Author: vladr,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-07-31 16:41:55

Jeśli chcesz mieć taką samą prędkość jak explorer, dlaczego nie użyć skryptów windows, aby uzyskać dostęp do tej samej funkcjonalności za pomocą pythoncom np.

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

Będzie działać tak samo jak explorer, więcej o skryptach można przeczytać na stronie http://msdn.microsoft.com/en-us/library/bstcxhf7 (VS.85). aspx .

 20
Author: Anurag Uniyal,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-10-17 13:15:40

Porównałem wydajność kodu Pythona z 15K drzewem katalogów zawierającym 190K plików i porównałem go z poleceniem du(1), które prawdopodobnie działa tak szybko jak system operacyjny. Kod Pythona zajął 3,3 sekundy w porównaniu do du, który zajął 0,8 sekundy. To było na Linuksie.

Nie jestem pewien, czy jest wiele do wyciśnięcia z kodu Pythona. Zauważ też, że pierwsze uruchomienie du trwało 45 sekund, co było oczywiście zanim odpowiednie i-węzły znalazły się w pamięci podręcznej bloku; dlatego to wydajność w dużym stopniu zależy od tego, jak dobrze system zarządza swoim sklepem. Nie zdziwiłoby mnie to, gdyby jedno i drugie:

  1. os./ align = "left" / getsize jest nieoptymalny w systemie Windows
  2. Windows buforuje Rozmiar zawartości katalogu po obliczeniu
 5
Author: msw,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-03-21 03:41:47