很快得到文件夹的总大小

use*_*459 51 python directory optimization

我想使用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)
Run Code Online (Sandbox Code Playgroud)

这是我编写的简单脚本来获取文件夹的总大小,花了大约60秒(+ -5秒).通过使用多处理,我在四核机器上将其降低到23秒.

使用Windows文件浏览器只需约3秒钟(右键单击 - >属性可自行查看).那么是否有更快的方法来查找接近Windows可以执行的速度的文件夹的总大小?

Windows 7,python 2.6(搜索但是大多数时候人们使用了与我自己非常相似的方法)在此先感谢.

vla*_*adr 76

你处于劣势.

Windows资源管理器几乎肯定使用FindFirstFile/ FindNextFile遍历目录结构lpFindFileData在一次传递中收集大小信息(通过),从而使每个文件基本上是单个系统调用.

遗憾的是,在这种情况下,Python不是你的朋友.从而,

  1. os.walk 第一次调用os.listdir(内部调用FindFirstFile/ FindNextFile)
    • 从这一点开始进行的任何其他系统调用只能使您比Windows资源管理器
  2. os.walk 然后调用isdir返回的每个文件os.listdir(内部调用GetFileAttributesEx- 或者,在Win2k之前,GetFileAttributes+ FindFirstFile组合)重新确定是否递归
  3. os.walkos.listdir将执行额外的内存分配,串和阵列操作等填写它们的返回值
  4. 然后getsize调用返回的每个文件os.walk(再次调用GetFileAttributesEx)

这是每个文件比Windows资源管理器多3倍的系统调用,加上内存分配和操作开销.

你可以使用Anurag的解决方案,也可以尝试直接和递归地调用FindFirstFile/ FindNextFile(这应该与一个cygwin或其他win32端口 的性能相当du -s some_directory.)

请参阅os.py的实施os.walk,posixmodule.c为实施listdirwin32_stat(双方调用isdirgetsize.)

请注意,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上).您可以在PyPI上使用scandir模块来获取旧版Python的这种行为,包括2.x.


Anu*_*yal 22

如果您想要与资源管理器相同的速度,为什么不使用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))
Run Code Online (Sandbox Code Playgroud)

它将与资源管理器相同,您可以在http://msdn.microsoft.com/en-us/library/bstcxhf7(VS.85).aspx上阅读有关Scripting运行时的更多信息.

  • 这实际上很棒,很棒.但只是大部分时间.在一个大小为37GB和7 000个文件的目录('C:\ Downloads')中,您的方法几乎可以立即得到结果.os.walk()方式会在几秒钟(3秒)内得到结果但是我在其他目录上遇到了一些问题,比如C:\ Windows,C:\ users等,它说发生了异常. (2认同)

msw*_*msw 5

我将Python代码的性能与包含190k文件的15k目录树进行了比较,并将其与du(1)可能与操作系统一样快的命令进行了比较.与du相比,Python代码耗时3.3秒,耗时0.8秒.这是在Linux上.

我不确定有多少东西可以挤出Python代码.另请注意,du的第一次运行需要45秒,这显然是在相关的i节点位于块缓存之前; 因此,这种性能在很大程度上取决于系统管理其商店的程度.如果其中一个或两个都不会让我感到惊讶:

  1. os.path.getsize在Windows上是次优的
  2. Windows一旦计算就缓存目录内容大小

  • 看起来它在Windows上确实较慢,在具有23K目录树和175K文件的窗口上花费大约60秒.使用相同的du windows需要6秒才能完成.所以看起来Python在Windows上比du慢10倍,在linux上慢4倍.所以,似乎1. os.path.getsize/os.walk在Windows 2上确实是次优的.Windows确实缓存目录内容大小3.Windows仍然比linux慢 (2认同)