很快得到文件夹的总大小

时间:2010-03-21 02:54:57

标签: python optimization directory

我想使用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(搜索但是大多数时候人们使用了与我自己非常相似的方法) 提前谢谢。

3 个答案:

答案 0 :(得分:74)

你处于劣势。

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
  5. 这是每个文件比Windows资源管理器多3倍的系统调用,加上内存分配和操作开销。

    您可以使用Anurag的解决方案,也可以尝试直接和递归地调用FindFirstFile / FindNextFile(这应该与cygwin或其他win32 port的效果相媲美du -s some_directory。)

    有关os.walklistdir的实施,win32_statos.py的实施,请参阅posixmodule.c(由isdirgetsize调用os.walk。)

    请注意,Python的 os.walk在所有平台(Windows和* nices)上都不是最理想的,包括Python3.1。在Windows和* n isdir上,FindFirst / FindNext(Windows)和opendir / {{readdir可以在一次通过中实现遍历,而无需调用lpFindFileData->dwFileAttributes 1}}(* nix)已经通过dirent::d_type(Windows)和GetFileAttributesEx(* nix)返回文件类型。

    也许违反直觉,在大多数现代配置(例如Win7和NTFS,甚至一些SMB实现)FindFirstFile 两次与单个文件的FindNextFile一样慢(可能甚至比使用os.walk()迭代目录要慢。)

    更新: Python 3.5包含新的PEP 471 os.scandir()函数,它通过返回文件属性和文件名来解决此问题。这个新函数用于加速内置{{1}}(在Windows和Linux上)。您可以使用scandir module on PyPI来获取旧版Python的此行为,包括2.x。

答案 1 :(得分:21)

如果您想要与资源管理器相同的速度,为什么不使用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阅读有关脚本运行时的更多信息。

答案 2 :(得分:5)

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

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

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