Python: os.stat().st_size给出的值与du命令不同

8
我正在创建一个实用程序,将遍历目录并获取所有子目录和文件的大小并存储该值。但是,大小计算不正确。
这是我的类,它会自动递归遍历所有子目录:
class directory:
    '''
    Class that automatically traverses directories
    and builds a tree with size info
    '''
    def __init__(self, path, parent=None):

        if path[-1] != '/':
            # Add trailing /
            self.path = path + '/'
        else:
            self.path = path
        self.size = 4096
        self.parent = parent
        self.children = []
        self.errors = []
        for i in os.listdir(self.path):
            try:
                self.size += os.lstat(self.path + i).st_size
                if os.path.isdir(self.path + i) and not os.path.islink(self.path + i):
                    a = directory(self.path + i, self)
                    self.size += a.size
                    self.children.append(a)
            except OSError:
                self.errors.append(path + i)

我有一个视频目录,我正在使用这个程序进行测试:

>>> a = directory('/var/media/television/The Wire')
>>> a.size
45289964053

然而,当我尝试使用du命令时,我得到了以下结果。
$ du -sx /var/media/television/The\ Wire
44228824

这些目录不含任何链接或特殊内容。

有人能解释一下为什么os.stat()会给出奇怪的大小读数吗?

平台:

  • Linux(Fedora 13)
  • Python 2.7
4个回答

10
考虑这个名为foo的文件。
-rw-rw-r-- 1 unutbu unutbu 25334 2010-10-31 12:55 foo

这段文字意思是:它由25334个字节组成。

tune2fs告诉我foo所在的文件系统块大小为4096个字节:

% sudo tune2fs -l /dev/mapper/vg1-OS1
...
Block size:               4096
...

因此,即使文件内容只有1个字节,文件系统上最小的文件也会占用4096个字节。随着文件变得越来越大,空间将以4096字节块的形式分配。

du报告

% du -B1 foo
28672   foo

请注意,28672/4096 = 7。这意味着foo在文件系统上占用了7个4096字节块。这是存储25334字节所需的最小块数。
% du foo
28  foo

这个版本的 du 只是报告 28672/1024 向下取整后的结果。


所以du报告分配块数*块大小=磁盘上的大小,而Python报告确切的大小,对吗? - fandingo

1

du 默认情况下返回磁盘上的文件大小,而非 st_size 给出的实际文件大小。

$ du test.txt
    8    test.txt

$ du -b test.txt
    6095 test.txt


>>> os.stat('test.txt').st_size
6095

0
我会将这段代码写成这样:
import os, os.path

def size_dir(d):
    file_walker = (
        os.path.join(root, f)
        for root, _, files in os.walk(d)
        for f in files
    )
    return sum(os.path.getsize(f) for f in file_walker)

如果你想将目录计算为4k,那么可以像这样做:
import os, os.path

def size_dir(d):
    file_walker = (
        os.path.join(root, f)
        for root, _, files in os.walk(d)
        for f in files
    )
    dir_walker = (
        4096
        for root, dirs, _ in os.walk(d)
        for d in dirs
    )
    return 4096 + sum(os.path.getsize(f) for f in file_walker) + sum(size for size in dir_walker)

0
在Linux上(我使用的是CentOS),'du -b'将以字节返回并激活--apparent-size,从而返回文件的大小而不是它正在使用的磁盘空间量。尝试一下,看看这是否与Python os.stat所说的一致。

谢谢,离正解很接近,但还不够准确。 - fandingo

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接