关于python:看似shutil.disk_usage()中的差异

Seeming discrepancy in shutil.disk_usage()

大家好,StackOverflow,长期读者,第一次海报。希望我有足够的信息来提出一个有用的问题。

我正在使用shutil.disk_usage()函数查找特定路径的当前磁盘使用情况(可用数量、已用数量等)。据我所知,这是一个围绕os.statvfs()调用的包装器。我发现,与Linux中的"du"输出相比,它没有给出我所期望的答案。

出于公司隐私的原因,我隐藏了下面的一些路径,但是输出和代码在其他方面是未经处理的。我使用的是Python3.3.2 64位版本。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
#!/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))

输出:

1
2
3
4
5
/data/foo/drivecode/me % disk_usage_test.py
Total: 609.60GB
Used:  291.58GB
Total: 609.60GB
Used:  291.58GB

如您所见,主要问题是我希望"used"的第二个数量要小得多,因为它是第一个目录的子集。

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

尽管我非常信任"du",但我发现很难相信python模块也会不正确。因此,可能是我对Linux文件系统的理解造成了问题。:)

我编写了一个模块(很大程度上基于So中某人的代码),它递归地获取磁盘使用情况,直到现在我才使用。它看起来与"du"输出相匹配,但是比shutil.disk的usage()函数慢得多,所以我希望我能使它正常工作。

提前多谢。


问题是Shutil使用下面的statvfs系统调用来确定使用的空间。据我所知,这个系统调用没有文件路径粒度,只有文件系统粒度。这意味着,您提供的路径只有助于标识要查询的文件系统,而不是路径。

换句话说,您给它指定了路径/data/foo/utils,然后它确定哪个文件系统支持这个文件路径。然后查询文件系统。当您考虑如何在shutil中定义used参数时,这变得很明显:

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

在哪里?

1
2
3
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命令的源代码。


shutil.disk_usage返回磁盘使用情况(即返回路径的装入点),而不是该路径下的实际文件使用情况。它相当于运行df /path/to/mount,而不是du /path/to/files。注意,对于这两个目录,您得到了完全相同的用法。

从文档:"返回给定路径的磁盘使用统计信息,作为具有total、used和free属性的命名元组,以字节为单位,表示总空间、已用空间和可用空间的数量。"