linux shutil.disk_usage()中似乎存在差异

p4rjhz4m  于 2023-06-05  发布在  Linux
关注(0)|答案(4)|浏览(536)

我使用shutil.disk_usage()函数来查找特定路径的当前磁盘使用情况(可用量、已使用量等)。据我所知,这是一个围绕os.statvfs()调用的 Package 器。我发现它没有给出我所期望的答案,与Linux中的“du”的输出相比。
出于公司隐私的原因,我隐藏了下面的一些路径,但输出和代码是未经修改的。Python 3.3.2 64位版本

#!/apps/python/3.3.2_64bit/bin/python3

# test of shutils.diskusage module
import shutil

BytesPerGB = 1024 * 1024 * 1024

(total, used, free) = shutil.disk_usage("/data/foo/")
print ("Total: %.2fGB" % (float(total)/BytesPerGB))
print ("Used:  %.2fGB" % (float(used)/BytesPerGB))

(total1, used1, free1) = shutil.disk_usage("/data/foo/utils/")
print ("Total: %.2fGB" % (float(total1)/BytesPerGB))
print ("Used:  %.2fGB" % (float(used1)/BytesPerGB))

其输出:

/data/foo/drivecode/me % disk_usage_test.py
Total: 609.60GB
Used:  291.58GB
Total: 609.60GB
Used:  291.58GB

正如您所看到的,主要问题是我希望“Used”的第二个数量要小得多,因为它是第一个目录的子集。

/data/foo/drivecode/me % du -sh /data/foo/utils
2.0G    /data/foo/utils

尽管我很信任“du”,但我发现很难相信Python模块也会不正确。因此,也许这只是我对Linux文件系统的理解可能是问题所在。:)
我写了一个模块(主要基于SO上某人的代码),它递归地获取disk_usage,我一直使用到现在。它看起来与“du”输出匹配,但比shutil.disk_usage()函数慢得多,所以我希望我能让它工作。
先谢谢你了。

g52tjvyc

g52tjvyc1#

问题是shutil使用下面的statvfs系统调用来确定所使用的空间。据我所知,这个系统调用没有文件路径粒度,只有文件系统粒度。这意味着您提供给它的路径只能帮助识别您想要查询的文件系统,而不是路径。
换句话说,您为它提供了路径/data/foo/utils,然后它确定哪个文件系统支持此文件路径。然后它查询 * 文件系统 *。当您考虑used参数在shutil中是如何定义的时,这一点就变得显而易见了:

used = (st.f_blocks - st.f_bfree) * st.f_frsize

其中:

fsblkcnt_t     f_blocks;   /* size of fs in f_frsize units */
fsblkcnt_t     f_bfree;    /* # free blocks */
unsigned long  f_frsize;   /* fragment size */

这就是为什么它会提供整个文件系统上使用的 * 总 * 空间。
实际上,在我看来,du命令本身也会遍历文件结构并将文件大小相加。下面是GNU coreutils du命令的source code

iyzzxitl

iyzzxitl2#

shutil.disk_usage返回磁盘使用情况(即支持该路径的安装点),而不是该路径下的实际文件使用。这相当于运行df /path/to/mount而不是du /path/to/files。请注意,这两个目录的用法完全相同。
从文档:以命名元组的形式返回有关给定路径的磁盘使用情况统计信息,该命名元组具有属性total、used和free,这些属性是总空间、已用空间和可用空间的量(以字节为单位)。

iezvtpos

iezvtpos3#

2013年后,任何人都可以在此更新:
根据您的Python版本和操作系统,shutil.disk_usage可能支持path变量的文件和目录。以下是细分:

Windows:

  • 3.3 - 3.5:仅支持挂载点/文件系统
  • 3.6 - 3.7:目录支持
  • 3.8+:文件和目录支持
    Unix:
  • 3.3 - 3.5:仅支持挂载点/文件系统
  • 3.6+:文件和目录支持
41ik7eoe

41ik7eoe4#

由于上面已经提到这个函数报告的是disk_usage(顾名思义),而不是特定文件夹的数据使用情况,我冒昧地整理了一个非常简单明了的几行代码来计算文件夹大小。因为它是递归的;如果一个文件夹中有数十亿个文件,可能会花费一段时间/使用一点内存。

from pathlib import Path
from itertools import tee

def scandir(p: Path) -> int:
  files, dirs = tee(Path(p).iterdir())
  total = sum(x.stat().st_size for x in files if x.is_file())
  total += sum(scandir(x) for x in dirs if x.is_dir())
  return total
  
  
print(scandir('.'))  # path size in bytes

相关问题