Я хочу быстро найти общий размер любой папки с помощью Python.
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)
Это - простой сценарий, который я записал для получения общего размера папки, потребовалось приблизительно 60 секунд (+-5 секунд). При помощи многопроцессорной обработки я свалил его к 23 секундам на четырехъядерной машине.
Используя файловый менеджер Windows требуется только ~3 секунды (Щелчок правой кнопкой-> свойства, чтобы лично убедиться). Так есть ли более быстрый способ найти общий размер папки близко к скорости, что окна могут сделать это?
Windows 7, python 2.6 (Сделал поиски, но большую часть времени люди привыкли очень похожий метод для моего собственного), Заранее спасибо.
Вы находитесь в невыгодном положении.
Проводник Windows почти наверняка использует FindFirstFile
/ FindNextFile
для просмотра структуры каталогов и для сбора информации о размере (через lpFindFileData
) в за один проход, что по сути является одним системным вызовом для каждого файла.
К сожалению, Python в данном случае вам не друг. Таким образом,
os.walk
сначала вызывает os.listdir
(который внутренне вызывает FindFirstFile
/ FindNextFile
)
{{1 }} os.walk
, затем вызывает isdir
для каждого файла, возвращаемого ] os.listdir
(который внутренне вызывает GetFileAttributesEx
- или, до Win2k, комбинацию GetFileAttributes
+ FindFirstFile
), чтобы повторно определить, следует ли выполнять рекурсию или not os.walk
и os.listdir
будет выполнять дополнительное выделение памяти , операции со строками и массивами и т. д.чтобы заполнить их возвращаемое значение getsize
для каждого файла, возвращаемого os.walk
(который снова вызывает GetFileAttributesEx
) Это в 3 раза больше системных вызовов на файл, чем в проводнике Windows, плюс накладные расходы на выделение памяти и манипуляции.
Вы можете использовать решение Анурага или попробовать вызвать FindFirstFile
/ FindNextFile
напрямую и рекурсивно (что должно быть сопоставимо с производительностью cygwin
или другой порт win32 du -s some_directory
.)
Обратитесь к os.py
для реализации os.walk
, posixmodule .c
для реализации listdir
и win32_stat
(вызывается как isdir
, так и getsize
.)
Обратите внимание, что Python os.walk
не оптимален на всех платформах (Windows и * nices), вплоть до Python3.1. Как в Windows, так и в * nices os.walk
может выполнить обход за один проход без вызова isdir
, поскольку оба FindFirst
/ FindNext
(Windows ) и opendir
/ readdir
(* nix) уже возвращают тип файла через lpFindFileData-> dwFileAttributes
(Windows) и dirent :: d_type
(* nix).
Возможно, что парадоксально, но в большинстве современных конфигураций (например,Win7 и NTFS, и даже некоторые реализации SMB) GetFileAttributesEx
вдвое медленнее, чем FindFirstFile
одного файла (возможно, даже медленнее, чем итерация по каталогу с FindNextFile
.)
Обновление: Python 3.5 включает новую функцию PEP 471 os.scandir ()
, которая решает эту проблему, возвращая атрибуты файла вместе с именем файла. . Эта новая функция используется для ускорения встроенной os.walk ()
(как в Windows, так и в Linux). Вы можете использовать модуль scandir в PyPI , чтобы получить такое поведение для более старых версий Python, включая 2.x.
Если вам нужна такая же скорость, как у проводника, почему бы не использовать сценарии Windows для доступа к той же функциональности с использованием pythoncom, например.
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))
Он будет работать так же, как проводник, вы можете узнать больше о среде выполнения сценариев на http://msdn.microsoft.com/en-us/library/bstcxhf7 (VS.85) .aspx .
Я сравнил производительность кода Python с деревом каталогов размером 15k, содержащим 190k файлов, и сравнил его с командой du(1)
, которая, предположительно, работает примерно так же быстро, как ОС. Код Python занял 3,3 секунды по сравнению с командой du, которая заняла 0,8 секунды. Это было на Linux.
Я не уверен, что из кода Python можно извлечь много пользы. Заметим также, что первый запуск du занял 45 секунд, что было очевидно до того, как соответствующие i-узлы оказались в блочном кэше; поэтому производительность сильно зависит от того, насколько хорошо система управляет своим хранилищем. Я не удивлюсь, если либо одно, либо другое: