我想知道在 Windows 操作系统 pc 上用 python 获取文件夹/目录大小(以字节为单位,稍后我会将它们格式化为另一种大小)的最快方法是什么。我当前使用的 python 版本是 3.8。我在 python 中尝试了以下函数来获取它:
def get_dir_size(directory):
total = 0
try:
for entry in os.scandir(directory):
if entry.is_file():
total += os.path.getsize(entry.path)
elif entry.is_dir():
total += get_directory_size(entry.path)
except NotADirectoryError:
return os.path.getsize(directory)
return total
但是,我意识到上面的代码运行时间太长,因为我有相当多的文件夹来计算它的大小,而一个有很多子文件夹的大文件夹会占用很多时间来计算整体大小。
相反,我尝试了各种方法,但遇到了当前方法的障碍。在这种方法中,我尝试使用 subprocess.run 运行 powershell 命令并获取大小。这是我为此编写的代码:
folder_path = C:\Users\username\Downloads\test_folder # Suppose this path is a legitimate path
command = fr"Get-ChildItem -Path {folder_path} -Recurse -ErrorAction SilentlyContinue | Measure-Object -Property Length -Sum | Select-Object Sum, Count"
proc = subprocess.run(command, shell=True, stdout=subprocess.PIPE)
print(proc.stdout)
我打印
proc.stdout
时得到的最终输出是空的,并打印错误说我给出的命令是not recognized as an internal or external command, operable program or batch file
.
如果我能得到一些关于如何使这项工作的建议,或者如果可能的话,提供关于如何在尽可能短的时间内获得文件夹大小的建议,我将不胜感激。我目前可行的方法需要花费太多时间,并且在网络之间可能会被切断。
谢谢。
我最近遇到了和你一样的问题。虽然可能还有其他最佳解决方案,但这是我的处理方式。但在此之前,我想提一下“子流程”包文档指出:
在带有
的 Windows 上,“COMSPEC 环境变量” 指定默认 shell。shell=True
通常,此变量默认设置为
cmd.exe
,这意味着传递给subprocess.run()
的任何命令都将在命令提示符下执行。这就是为什么当您尝试运行 powershell cmdlet Get-ChildItem
时,cmd 无法识别它,从而导致该错误消息。
因此,要执行您在 cmd 中的 PowerShell 命令,请使用
-Command
参数 调用 PowerShell 进程,如下所示:
command = f"powershell -command \"(Get-ChildItem -Force -Path '{folder_path}' -Recurse -ErrorAction SilentlyContinue | measure -Property Length -Sum).sum\""
注意额外的
-Force
参数,它允许 cmdlet 获取用户通常无法访问的项目(即需要管理员权限),例如隐藏文件或系统文件。
但是,在我进行速度测试后,我发现在处理包含相对较少文件的
文件夹时,这种方法比os.walk()
方法慢。这可能归因于 PowerShell 界面在执行命令之前在后台加载所需的时间(尽管我不确定这一点)。速度测试是通过以下方法进行的:
以下是我的基准测试结果:
文件夹大小 | childitem_method | walk_method | dir_method |
---|---|---|---|
1 Gb(2 项) | 1.6201 秒 | 0.0013秒 | 0.1968 秒 |
6 Gb(60 项) | 1.6853 秒 | 0.0179 秒 | 0.2020 秒 |
3 Gb(1000 项) | 1.9482 秒 | 0.2969 秒 | 0.2832 秒 |
10 Gb(10000 项) | 4.5680 秒 | 2.8583 秒 | 2.0390 秒 |
27 Gb(15000 项) | 6.1768 秒 | 4.7842 秒 | 2.8775 秒 |
77 Gb(670000 项) | 6 分钟:30 秒 | 8 分钟:17 秒 | 3 分钟:37 秒 |
下面是我使用的三种方法的实现:
import os
import subprocess
import re
import timeit
def childitem_method(path):
if os.path.isdir(path):
command = f"powershell -command \"(Get-ChildItem -Force -Path '{path}' -Recurse -ErrorAction SilentlyContinue | measure -Property Length -Sum).sum\""
output = (
subprocess.check_output(command, shell=True)
.decode("utf-8", errors="ignore")
.strip()
)
return int(output) if output.isnumeric() else None
def walk_method(path):
if os.path.isdir(path):
return sum(
sum(
os.path.getsize(os.path.join(walk_result[0], element))
for element in walk_result[2]
)
for walk_result in os.walk(path)
)
def dir_method(path):
if os.path.isdir(path):
command = f'chcp 65001 > nul && dir "{path}" /s /a /-C'
output = (
subprocess.check_output(command, shell=True)
.decode("utf-8", errors="ignore")
.strip()
.rsplit("\n", 2)[1]
)
output = re.findall(r"\d+", output)[-1]
return int(output) if output.isnumeric() else None
if __name__ == "__main__":
folder_path, repetitions = r"C:\ ".strip(), 100
print("childitem_method:",
timeit.timeit(lambda: childitem_method(folder_path), number=repetitions)/repetitions)
print("walk_method: ",
timeit.timeit(lambda: walk_method(folder_path), number=repetitions)/repetitions)
print("dir_method: ",
timeit.timeit(lambda: dir_method(folder_path), number=repetitions)/repetitions)