Подтвердить что ты не робот

Очень быстро получить общий размер папки

Я хочу быстро найти общий размер любой папки, использующей 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 секунды (см. Свойства click->, чтобы убедиться в этом). Так есть ли более быстрый способ найти общий размер папки, близкий к скорости, с которой Windows может это сделать?

Windows 7, python 2.6 (делал поиски, но большую часть времени люди использовали очень похожий метод с моим) Заранее спасибо.

4b9b3361

Ответ 1

Вы находитесь в невыгодном положении.

Проводник Windows почти наверняка использует FindFirstFile/FindNextFile, чтобы обойти структуру каталогов и собирать информацию о размере (через lpFindFileData) за один проход, что делает по существу один системный вызов для каждого файла.

В этом случае Python, к сожалению, не ваш друг. Таким образом,

  • os.walk первые вызовы os.listdir (который внутренне вызывает FindFirstFile/FindNextFile)
    • любые дополнительные системные вызовы, сделанные с этой точки дальше, могут сделать вас медленнее, чем проводник Windows
  • os.walk затем вызывает isdir для каждого файла, возвращаемого os.listdir (который внутренне вызывает GetFileAttributesEx - или, прежде чем Win2k, a GetFileAttributes + FindFirstFile комбо), чтобы переопределить, следует ли повторять или нет
  • os.walk и os.listdir будут выполнять выделение дополнительной памяти, операции с строками и массивами и т.д., чтобы заполнить их возвращаемое значение
  • вы , затем вызовите getsize для каждого файла, возвращаемого os.walk (который снова вызывает GetFileAttributesEx)

Это 3 раза больше системных вызовов на файл, чем проводник Windows, плюс распределение памяти и накладные расходы.

Вы можете либо использовать решение Anurag, либо попытаться вызвать 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.

Ответ 2

Если вам нужна такая же скорость, как и проводник, почему бы не использовать сценарии 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.

Ответ 3

Я сравнивал производительность кода Python с деревом каталогов на 15 тыс., содержащим файлы 190 тыс., и сравнивал его с командой du(1), которая, предположительно, происходит так же быстро, как и ОС. Код Python занял 3,3 секунды по сравнению с дю, который занял 0,8 секунды. Это было на Linux.

Я не уверен, что есть много, чтобы выжать из кода Python. Заметим также, что первый запуск du занял 45 секунд, что было очевидно, прежде чем соответствующие i-узлы были в кеше блока; поэтому эта производительность сильно зависит от того, насколько хорошо система управляет своим магазином. Меня это не удивит, если один или оба:

  • os.path.getsize является субоптимальным в Windows
  • Windows подсчитывает размер содержимого каталога после расчёта