在Windows上用Python快速计算文件夹大小
我在找一种快速的方法,用Python在Windows上计算一个文件夹的大小。到目前为止,我有以下代码:
def get_dir_size(path):
total_size = 0
if platform.system() == 'Windows':
try:
items = win32file.FindFilesW(path + '\\*')
except Exception, err:
return 0
# Add the size or perform recursion on folders.
for item in items:
attr = item[0]
name = item[-2]
size = item[5]
if (attr & win32con.FILE_ATTRIBUTE_DIRECTORY) and \
not (attr & win32con.FILE_ATTRIBUTE_SYSTEM): # skip system dirs
if name not in DIR_EXCLUDES:
total_size += get_dir_size("%s\\%s" % (path, name))
total_size += size
return total_size
但是当文件夹的大小超过100G时,这个方法就不够好了。有没有什么办法可以改进一下?
在一台性能不错的电脑上(2GHz以上,5G内存),我花了72秒来处理422GB的数据,里面有226,001个文件和12,043个文件夹。而使用资源管理器的属性选项则只需要40秒。
我知道我有点贪心,但我希望能找到一个更好的解决方案。
Laurent Luce
6 个回答
这个目录树真是庞大啊。正如其他人所说的,我不太确定你能否加快它的速度……没有数据的情况下是没办法的。这意味着……
如果你能以某种方式缓存数据(我不太清楚具体的含义是什么),那么你可能可以加快速度(我想……一如既往,测量、测量、再测量)。
我想我不需要告诉你怎么做缓存,你看起来对这方面挺了解的。而且我也不太清楚Windows上该怎么做。;-)
如果你使用os.walk,就不需要用递归算法了。可以看看这个问题。
你应该对这两种方法的速度进行测试,不过这种方法应该会快很多:
import os
def get_dir_size(root):
size = 0
for path, dirs, files in os.walk(root):
for f in files:
size += os.path.getsize( os.path.join( path, f ) )
return size
快速分析你的代码显示,超过90%的时间都花在了FindFilesW()
这个调用上。这意味着,如果只是调整Python代码,得到的改进会非常有限。
一些小的调整(如果你继续使用FindFilesW)可以包括确保DIR_EXCLUDES是一个集合而不是列表,避免在其他模块上重复查找,以及懒惰地索引item[],还有把sys.platform的检查移到外面。这些改动和其他一些改动结合起来,但速度提升不会超过1-2%。
DIR_EXCLUDES = set(['.', '..'])
MASK = win32con.FILE_ATTRIBUTE_DIRECTORY | win32con.FILE_ATTRIBUTE_SYSTEM
REQUIRED = win32con.FILE_ATTRIBUTE_DIRECTORY
FindFilesW = win32file.FindFilesW
def get_dir_size(path):
total_size = 0
try:
items = FindFilesW(path + r'\*')
except pywintypes.error, ex:
return total_size
for item in items:
total_size += item[5]
if (item[0] & MASK == REQUIRED):
name = item[8]
if name not in DIR_EXCLUDES:
total_size += get_dir_size(path + '\\' + name)
return total_size
唯一能带来显著速度提升的方法是使用不同的API或者不同的技术。你在评论中提到过要在后台进行这个操作,所以你可以考虑使用一些监控文件夹变化的包,来进行增量更新。可能可以使用FindFirstChangeNotification API或者类似的东西。你可以设置监控整个目录树,或者根据这个程序的工作方式(我没用过)来决定是否在整个树的不同子集上注册多个请求,这样可以减少你在收到通知后需要搜索的内容,以确定实际发生了什么变化以及现在的大小。
编辑:我在评论中问过你是否考虑到了Windows XP及以后的系统重度缓存文件系统元数据。我刚刚检查了你的代码(和我的代码)在Windows上的表现,选择了我C:\文件夹中的所有项目,然后按Alt-Enter打开属性窗口。在用你的代码执行一次后,耗时40秒,现在用两种方法都只需20秒。换句话说,你的代码实际上和Windows本身一样快,至少在我的机器上是这样。