Python: os.stat ().размер st дает другое значение, чем du

Я создаю утилиту, которая будет проходить через каталоги и получать размеры дочерних каталогов и файлов для всех каталогов и хранить значение. Однако размеры вычисляются неправильно.

вот, что автоматически повторяется через все подкаталоги:
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 ответов


рассмотрим этот файл 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
...

таким образом, самый маленький файл в файловой системе будет занимать 4096 байт, даже если его содержимое состоит всего из 1 байта. По мере увеличения файла пространство выделяется в 4096-байтовых блоках.

du reports

% du -B1 foo
28672   foo

обратите внимание, что 28672/4096 = 7. Это говорит о том, что Foo оккуписа 7 4096-байтовых блоков в файловой системе. Это наименьшее количество блоков, необходимых для хранения 25334 байт.

% du foo
28  foo

эта версия du просто сообщает 28672/1024 округлено вниз.


du дает размер на диске по умолчанию, по сравнению с фактическим размером файла, как указано в st_size.

$ du test.txt
    8    test.txt

$ du -b test.txt
    6095 test.txt


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

Я бы написал этот код:

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)

в linux (я использую CentOS),' du-b ' вернется в байтах и активирует --apparent-size таким образом, возвращая размер файла, а не объем дискового пространства, которое он использует. Попробуйте это и посмотрите, согласуется ли это с тем, что Python os.stat говорит.