在 Windows pc 上用 python 获取文件夹大小的最快方法是什么

问题描述 投票:0回答:1

我想知道在 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
.

如果我能得到一些关于如何使这项工作的建议,或者如果可能的话,提供关于如何在尽可能短的时间内获得文件夹大小的建议,我将不胜感激。我目前可行的方法需要花费太多时间,并且在网络之间可能会被切断。

谢谢。

python-3.x windows directory subprocess size
1个回答
0
投票

我最近遇到了和你一样的问题。虽然可能还有其他最佳解决方案,但这是我的处理方式。但在此之前,我想提一下“子流程”包文档指出:

在带有

shell=True
的 Windows 上,“COMSPEC 环境变量” 指定默认 shell。

通常,此变量默认设置为

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 界面在执行命令之前在后台加载所需的时间(尽管我不确定这一点)。速度测试是通过以下方法进行的:

  1. Get-ChildItem,(powershell)
  2. os.walk(),(蟒蛇)
  3. dir,(一个内置的 cmd 命令)

以下是我的基准测试结果:

文件夹大小 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)
© www.soinside.com 2019 - 2024. All rights reserved.