Вычислить размер каталога с помощью Python?


182

Прежде чем я заново изобрел этот конкретный круг, есть ли у кого-нибудь хорошая процедура для расчета размера каталога с использованием Python? Было бы очень хорошо, если бы подпрограмма хорошо форматировала размер в Мб / Гб и т. Д.


13
Это НЕ было бы очень хорошо. У вас должна быть одна функция для расчета размера и вполне независимая функция (которую можно использовать, например, с размерами памяти) для «удобного форматирования размера в Мб / Гб и т. Д.».
Джон Мачин

17
Да, я знаю, но это экономит, задавая два вопроса.
Гэри Уиллоуби

1
Команда treeв системах * nix делает все это бесплатно. tree -h -d --du /path/to/dir,
Мех

@mehdu -sh /path/to/dir/*
mrgloom

Ответы:


252

Это идет по всем подкаталогам; суммирование размеров файлов:

import os

def get_size(start_path = '.'):
    total_size = 0
    for dirpath, dirnames, filenames in os.walk(start_path):
        for f in filenames:
            fp = os.path.join(dirpath, f)
            # skip if it is symbolic link
            if not os.path.islink(fp):
                total_size += os.path.getsize(fp)

    return total_size

print(get_size(), 'bytes')

И еще один интересный способ использования os.listdir ( не включает подкаталоги ):

import os
sum(os.path.getsize(f) for f in os.listdir('.') if os.path.isfile(f))

Ссылка:

Обновлено Для использования os.path.getsize это более понятно , чем использование метода os.stat (). St_size.

Спасибо ghostdog74 за указание на это!

os.stat - st_size Дает размер в байтах. Может также использоваться для получения размера файла и другой информации, связанной с файлом.

import os

nbytes = sum(d.stat().st_size for d in os.scandir('.') if d.is_file())

Обновление 2018

Если вы используете Python 3.4 или более раннюю версию, вы можете рассмотреть возможность использования более эффективного walkметода, предоставляемого сторонним scandirпакетом. В Python 3.5 и более поздних версиях этот пакет был включен в стандартную библиотеку и os.walkполучил соответствующее увеличение производительности.

Обновление 2019

В последнее время я использую pathlibвсе больше и больше, вот pathlibрешение:

from pathlib import Path

root_directory = Path('.')
sum(f.stat().st_size for f in root_directory.glob('**/*') if f.is_file())

14
+1, но oneliner не возвращает действительный результат, потому что он не рекурсивный
luc

2
Да, это только для плоского случая каталога.
Monkut

35
Для реального удовольствия вы можете сделать рекурсивный размер в одну строку: sum (os.path.getsize (os.path.join (dirpath, filename)) для dirpath, dirnames, имена файлов в os.walk (PATH) для имени файла в именах файлов)
driax

2
Но вы должны использовать, st_sizeесли вы хотите не следовать символическим ссылкам, как вы должны затем использовать lstat.
asmeurer

3
Предупреждение! это не то же самое, что du-sb. Смотрите ответ Самуэля Лампы! Ваш код игнорирует размер папки, используемой для хранения FAT.
Евгений Якимович

43

Некоторые из предложенных подходов реализуют рекурсию, другие используют оболочку или не будут давать аккуратно отформатированные результаты. Когда ваш код является одноразовым для платформ Linux, вы можете получить обычное форматирование, включая рекурсию, в виде одной строки. За исключением printпоследней строки, она будет работать для текущих версий python2и python3:

du.py
-----
#!/usr/bin/python3
import subprocess

def du(path):
    """disk usage in human readable format (e.g. '2,1GB')"""
    return subprocess.check_output(['du','-sh', path]).split()[0].decode('utf-8')

if __name__ == "__main__":
    print(du('.'))

прост, эффективен и будет работать с файлами и многоуровневыми каталогами:

$ chmod 750 du.py
$ ./du.py
2,9M

13
В северном направлении Только для Linux
Meawoppl

15
Python, будучи кроссплатформенным по своей природе, вероятно, должен избегать этого
Джонатан

11
Спасибо за эти замечания. Я добавил некоторые предостережения относительно зависимости платформы от ответа. Тем не менее, большая часть кода Python, если одноразовые скрипты. Такой код не должен иметь функциональных ограничений, длинных и подверженных ошибкам переходов или необычных результатов в крайних случаях, просто ради переносимости сверх какой-либо необходимости . Это, как всегда, компромисс, и разработчик должен сделать правильный выбор;)
flaschbier

9
Nitpick: не Linux, а только для Unix / Posix :)
Мистер Акула

3
Вероятно, целесообразно добавить параметр '-x' в команду du, чтобы ограничить поиск файловой системой. Другими словами, используйте вместо этого ['du', '-shx', path].
Кит

24

Вот рекурсивная функция (она рекурсивно суммирует размер всех подпапок и их соответствующих файлов), которая возвращает точно такие же байты, что и при запуске du -sb. в Linux (где «.» означает «текущая папка»):

import os

def getFolderSize(folder):
    total_size = os.path.getsize(folder)
    for item in os.listdir(folder):
        itempath = os.path.join(folder, item)
        if os.path.isfile(itempath):
            total_size += os.path.getsize(itempath)
        elif os.path.isdir(itempath):
            total_size += getFolderSize(itempath)
    return total_size

print "Size: " + str(getFolderSize("."))

2
Эта функция также вычисляет размер символической ссылки - если вы хотите пропустить символические ссылки, вы должны проверить, что это не так: if os.path.isfile (itempath) и os.path.islink (itempath) и elif os.path.isdir ( itempath) и os.path.islink (itempath).
период с

17

Рекурсивный размер папки Python 3.5 с использованием os.scandir

def folder_size(path='.'):
    total = 0
    for entry in os.scandir(path):
        if entry.is_file():
            total += entry.stat().st_size
        elif entry.is_dir():
            total += folder_size(entry.path)
    return total

1
Однострочный метод Python 3, если не беспокоиться о рекурсивности sum([entry.stat().st_size for entry in os.scandir(file)]). Примечание выводится в байтах, / 1024 для получения КБ и / (1024 * 1024) для получения МБ.
weiji14

4
@ weiji14 потерять скобки, то есть sum(entry.stat().st_size for entry in os.scandir(file)). Нет причин составлять список, потому что sumпринимает итераторы.
Ведран Шего

8

Ответ monknut хорош, но он не работает на битой символической ссылке, поэтому вам также нужно проверить, действительно ли существует этот путь

if os.path.exists(fp):
    total_size += os.stat(fp).st_size

3
Вы, вероятно, не хотите переходить по символическим ссылкам. Вы должны использовать lstat.
asmeurer

8

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

import os
def get_size(start_path='.'):
    total_size = 0
    seen = {}
    for dirpath, dirnames, filenames in os.walk(start_path):
        for f in filenames:
            fp = os.path.join(dirpath, f)
            try:
                stat = os.stat(fp)
            except OSError:
                continue

            try:
                seen[stat.st_ino]
            except KeyError:
                seen[stat.st_ino] = True
            else:
                continue

            total_size += stat.st_size

    return total_size

print get_size()

5
Попробуйте использовать os.lstat(а не os.stat), чтобы избежать следующих символических ссылок: docs.python.org/2/library/os.html#os.lstat
Питер Бриггс

7

Ответ Криса хорош, но его можно сделать более идиоматичным, если использовать набор для проверки видимых каталогов, что также позволяет избежать использования исключения для потока управления:

def directory_size(path):
    total_size = 0
    seen = set()

    for dirpath, dirnames, filenames in os.walk(path):
        for f in filenames:
            fp = os.path.join(dirpath, f)

            try:
                stat = os.stat(fp)
            except OSError:
                continue

            if stat.st_ino in seen:
                continue

            seen.add(stat.st_ino)

            total_size += stat.st_size

    return total_size  # size in bytes

2
Ответ Криса также не учитывает символические ссылки и размеры самих каталогов. Я отредактировал ваш ответ соответственно, вывод фиксированной функции теперь идентичен df -sb.
Creshal

7

рекурсивный однострочник:

def getFolderSize(p):
   from functools import partial
   prepend = partial(os.path.join, p)
   return sum([(os.path.getsize(f) if os.path.isfile(f) else getFolderSize(f)) for f in map(prepend, os.listdir(p))])

1
Это не один лайнер, хотя. Однако он рекурсивно вычисляет размер папки (даже если в папке несколько папок) в байтах и ​​дает правильное значение.
Венкатеш


5

Для второй части вопроса

def human(size):

    B = "B"
    KB = "KB" 
    MB = "MB"
    GB = "GB"
    TB = "TB"
    UNITS = [B, KB, MB, GB, TB]
    HUMANFMT = "%f %s"
    HUMANRADIX = 1024.

    for u in UNITS[:-1]:
        if size < HUMANRADIX : return HUMANFMT % (size, u)
        size /= HUMANRADIX

    return HUMANFMT % (size,  UNITS[-1])

5

Используя pathlibэту строку, я получил размер одной папки:

sum(file.stat().st_size for file in Path(folder).rglob('*'))

И вот что я придумал для красиво отформатированного вывода:

from pathlib import Path


def get_folder_size(folder):
    return ByteSize(sum(file.stat().st_size for file in Path(folder).rglob('*')))


class ByteSize(int):

    _kB = 1024
    _suffixes = 'B', 'kB', 'MB', 'GB', 'PB'

    def __new__(cls, *args, **kwargs):
        return super().__new__(cls, *args, **kwargs)

    def __init__(self, *args, **kwargs):
        self.bytes = self.B = int(self)
        self.kilobytes = self.kB = self / self._kB**1
        self.megabytes = self.MB = self / self._kB**2
        self.gigabytes = self.GB = self / self._kB**3
        self.petabytes = self.PB = self / self._kB**4
        *suffixes, last = self._suffixes
        suffix = next((
            suffix
            for suffix in suffixes
            if 1 < getattr(self, suffix) < self._kB
        ), last)
        self.readable = suffix, getattr(self, suffix)

        super().__init__()

    def __str__(self):
        return self.__format__('.2f')

    def __repr__(self):
        return '{}({})'.format(self.__class__.__name__, super().__repr__())

    def __format__(self, format_spec):
        suffix, val = self.readable
        return '{val:{fmt}} {suf}'.format(val=val, fmt=format_spec, suf=suffix)

    def __sub__(self, other):
        return self.__class__(super().__sub__(other))

    def __add__(self, other):
        return self.__class__(super().__add__(other))

    def __mul__(self, other):
        return self.__class__(super().__mul__(other))

    def __rsub__(self, other):
        return self.__class__(super().__sub__(other))

    def __radd__(self, other):
        return self.__class__(super().__add__(other))

    def __rmul__(self, other):
        return self.__class__(super().__rmul__(other))   

Использование:

>>> size = get_folder_size("c:/users/tdavis/downloads")
>>> print(size)
5.81 GB
>>> size.GB
5.810891855508089
>>> size.gigabytes
5.810891855508089
>>> size.PB
0.005674699077644618
>>> size.MB
5950.353260040283
>>> size
ByteSize(6239397620)

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


4

Вы можете сделать что-то вроде этого:

import commands   
size = commands.getoutput('du -sh /path/').split()[0]

в этом случае я не проверял результат перед его возвратом, при желании вы можете проверить его с помощью command.getstatusoutput.


как производительность по сравнению с os.walkрекурсивной проверкой размера подпапки?
TomSawyer

4

Вы говорите, один вкладыш ... Вот один вкладыш:

sum([sum(map(lambda fname: os.path.getsize(os.path.join(directory, fname)), files)) for directory, folders, files in os.walk(path)])

Хотя я, вероятно, разделил бы это, и это не выполняет никаких проверок.

Чтобы преобразовать в КБ, см. Многоразовую библиотеку, чтобы получить читаемую человеком версию размера файла? и работать в


4

Немного опоздал на вечеринку, но в одной строке при условии, что у вас установлен glob2 и humanize . Обратите внимание, что в Python 3 по умолчанию iglobиспользуется рекурсивный режим. Как изменить код для Python 3 оставлено в качестве тривиального упражнения для читателя.

>>> import os
>>> from humanize import naturalsize
>>> from glob2 import iglob
>>> naturalsize(sum(os.path.getsize(x) for x in iglob('/var/**'))))
'546.2 MB'

1
Начиная с Python 3.5, встроенный globподдерживает рекурсию. Вы можете использовать:glob.glob('/var/**', recursive=True)
Adzenith

3

Следующий скрипт печатает размер каталога всех подкаталогов для указанного каталога. Он также пытается извлечь выгоду (если возможно) из кэширования вызовов рекурсивных функций. Если аргумент опущен, скрипт будет работать в текущем каталоге. Вывод сортируется по размеру каталога от самого большого до самого маленького. Таким образом, вы можете адаптировать его для своих нужд.

PS Я использовал рецепт 578019 для отображения размера каталога в удобном для человека формате ( http://code.activestate.com/recipes/578019/ )

from __future__ import print_function
import os
import sys
import operator

def null_decorator(ob):
    return ob

if sys.version_info >= (3,2,0):
    import functools
    my_cache_decorator = functools.lru_cache(maxsize=4096)
else:
    my_cache_decorator = null_decorator

start_dir = os.path.normpath(os.path.abspath(sys.argv[1])) if len(sys.argv) > 1 else '.'

@my_cache_decorator
def get_dir_size(start_path = '.'):
    total_size = 0
    if 'scandir' in dir(os):
        # using fast 'os.scandir' method (new in version 3.5)
        for entry in os.scandir(start_path):
            if entry.is_dir(follow_symlinks = False):
                total_size += get_dir_size(entry.path)
            elif entry.is_file(follow_symlinks = False):
                total_size += entry.stat().st_size
    else:
        # using slow, but compatible 'os.listdir' method
        for entry in os.listdir(start_path):
            full_path = os.path.abspath(os.path.join(start_path, entry))
            if os.path.isdir(full_path):
                total_size += get_dir_size(full_path)
            elif os.path.isfile(full_path):
                total_size += os.path.getsize(full_path)
    return total_size

def get_dir_size_walk(start_path = '.'):
    total_size = 0
    for dirpath, dirnames, filenames in os.walk(start_path):
        for f in filenames:
            fp = os.path.join(dirpath, f)
            total_size += os.path.getsize(fp)
    return total_size

def bytes2human(n, format='%(value).0f%(symbol)s', symbols='customary'):
    """
    (c) http://code.activestate.com/recipes/578019/

    Convert n bytes into a human readable string based on format.
    symbols can be either "customary", "customary_ext", "iec" or "iec_ext",
    see: http://goo.gl/kTQMs

      >>> bytes2human(0)
      '0.0 B'
      >>> bytes2human(0.9)
      '0.0 B'
      >>> bytes2human(1)
      '1.0 B'
      >>> bytes2human(1.9)
      '1.0 B'
      >>> bytes2human(1024)
      '1.0 K'
      >>> bytes2human(1048576)
      '1.0 M'
      >>> bytes2human(1099511627776127398123789121)
      '909.5 Y'

      >>> bytes2human(9856, symbols="customary")
      '9.6 K'
      >>> bytes2human(9856, symbols="customary_ext")
      '9.6 kilo'
      >>> bytes2human(9856, symbols="iec")
      '9.6 Ki'
      >>> bytes2human(9856, symbols="iec_ext")
      '9.6 kibi'

      >>> bytes2human(10000, "%(value).1f %(symbol)s/sec")
      '9.8 K/sec'

      >>> # precision can be adjusted by playing with %f operator
      >>> bytes2human(10000, format="%(value).5f %(symbol)s")
      '9.76562 K'
    """
    SYMBOLS = {
        'customary'     : ('B', 'K', 'M', 'G', 'T', 'P', 'E', 'Z', 'Y'),
        'customary_ext' : ('byte', 'kilo', 'mega', 'giga', 'tera', 'peta', 'exa',
                           'zetta', 'iotta'),
        'iec'           : ('Bi', 'Ki', 'Mi', 'Gi', 'Ti', 'Pi', 'Ei', 'Zi', 'Yi'),
        'iec_ext'       : ('byte', 'kibi', 'mebi', 'gibi', 'tebi', 'pebi', 'exbi',
                           'zebi', 'yobi'),
    }
    n = int(n)
    if n < 0:
        raise ValueError("n < 0")
    symbols = SYMBOLS[symbols]
    prefix = {}
    for i, s in enumerate(symbols[1:]):
        prefix[s] = 1 << (i+1)*10
    for symbol in reversed(symbols[1:]):
        if n >= prefix[symbol]:
            value = float(n) / prefix[symbol]
            return format % locals()
    return format % dict(symbol=symbols[0], value=n)

############################################################
###
###  main ()
###
############################################################
if __name__ == '__main__':
    dir_tree = {}
    ### version, that uses 'slow' [os.walk method]
    #get_size = get_dir_size_walk
    ### this recursive version can benefit from caching the function calls (functools.lru_cache)
    get_size = get_dir_size

    for root, dirs, files in os.walk(start_dir):
        for d in dirs:
            dir_path = os.path.join(root, d)
            if os.path.isdir(dir_path):
                dir_tree[dir_path] = get_size(dir_path)

    for d, size in sorted(dir_tree.items(), key=operator.itemgetter(1), reverse=True):
        print('%s\t%s' %(bytes2human(size, format='%(value).2f%(symbol)s'), d))

    print('-' * 80)
    if sys.version_info >= (3,2,0):
        print(get_dir_size.cache_info())

Пример вывода:

37.61M  .\subdir_b
2.18M   .\subdir_a
2.17M   .\subdir_a\subdir_a_2
4.41K   .\subdir_a\subdir_a_1
----------------------------------------------------------
CacheInfo(hits=2, misses=4, maxsize=4096, currsize=4)

РЕДАКТИРОВАТЬ: перемещен null_decorator выше, как рекомендуется пользователем 2233949


Ваш скрипт работает хорошо, но вам нужно переместить функцию null_decorator над строкой 'if sys.version_info> = ...'. В противном случае вы получите 'null_decorator' не определенное исключение. Прекрасно работает после этого, хотя.
user2233949

@ user2233949, спасибо! Я изменил код соответственно.
MaxU

3

используйте библиотеку sh : модуль duделает это:

pip install sh

import sh
print( sh.du("-s", ".") )
91154728        .

если вы хотите передать звездочку, используйте, globкак описано здесь .

чтобы преобразовать значения в удобочитаемые, используйте humanize :

pip install humanize

import humanize
print( humanize.naturalsize( 91157384 ) )
91.2 MB

2

для получения размера одного файла есть os.path.getsize ()

>>> import os
>>> os.path.getsize("/path/file")
35L

сообщается в байтах.


2

Для чего это стоит ... команда дерева делает все это бесплатно:

tree -h --du /path/to/dir  # files and dirs
tree -h -d --du /path/to/dir  # dirs only

Я люблю Python, но самое простое решение проблемы не требует нового кода.


@ Abdur-RahmaanJanhangeer, это правда. Это верно.
Мех

2

Это удобно:

import os
import stat

size = 0
path_ = ""
def calculate(path=os.environ["SYSTEMROOT"]):
    global size, path_
    size = 0
    path_ = path

    for x, y, z in os.walk(path):
        for i in z:
            size += os.path.getsize(x + os.sep + i)

def cevir(x):
    global path_
    print(path_, x, "Byte")
    print(path_, x/1024, "Kilobyte")
    print(path_, x/1048576, "Megabyte")
    print(path_, x/1073741824, "Gigabyte")

calculate("C:\Users\Jundullah\Desktop")
cevir(size)

Output:
C:\Users\Jundullah\Desktop 87874712211 Byte
C:\Users\Jundullah\Desktop 85815148.64355469 Kilobyte
C:\Users\Jundullah\Desktop 83803.85609722137 Megabyte
C:\Users\Jundullah\Desktop 81.83970321994275 Gigabyte

1

Я использую Python 2.7.13 с Scandir, и вот моя однострочная рекурсивная функция для получения общего размера папки:

from scandir import scandir
def getTotFldrSize(path):
    return sum([s.stat(follow_symlinks=False).st_size for s in scandir(path) if s.is_file(follow_symlinks=False)]) + \
    + sum([getTotFldrSize(s.path) for s in scandir(path) if s.is_dir(follow_symlinks=False)])

>>> print getTotFldrSize('.')
1203245680

https://pypi.python.org/pypi/scandir


1

Когда размер подкаталогов вычислен, он должен обновить размер папки своего родителя, и это будет продолжаться, пока не достигнет корневого родителя.

Следующая функция вычисляет размер папки и всех ее подпапок.

import os

def folder_size(path):
    parent = {}  # path to parent path mapper
    folder_size = {}  # storing the size of directories
    folder = os.path.realpath(path)

    for root, _, filenames in os.walk(folder):
        if root == folder:
            parent[root] = -1  # the root folder will not have any parent
            folder_size[root] = 0.0  # intializing the size to 0

        elif root not in parent:
            immediate_parent_path = os.path.dirname(root)  # extract the immediate parent of the subdirectory
            parent[root] = immediate_parent_path  # store the parent of the subdirectory
            folder_size[root] = 0.0  # initialize the size to 0

        total_size = 0
        for filename in filenames:
            filepath = os.path.join(root, filename)
            total_size += os.stat(filepath).st_size  # computing the size of the files under the directory
        folder_size[root] = total_size  # store the updated size

        temp_path = root  # for subdirectories, we need to update the size of the parent till the root parent
        while parent[temp_path] != -1:
            folder_size[parent[temp_path]] += total_size
            temp_path = parent[temp_path]

    return folder_size[folder]/1000000.0

1

Если вы находитесь в ОС Windows, вы можете сделать:

установите модуль pywin32, запустив:

pip install pywin32

а затем кодировать следующее:

import win32com.client as com

def get_folder_size(path):
   try:
       fso = com.Dispatch("Scripting.FileSystemObject")
       folder = fso.GetFolder(path)
       size = str(round(folder.Size / 1048576))
       print("Size: " + size + " MB")
   except Exception as e:
       print("Error --> " + str(e))

1

Вот одна строка, которая делает это рекурсивно (рекурсивная опция доступна в Python 3.5):

import os
import glob
print(sum(os.path.getsize(f) for f in glob.glob('**', recursive=True) if os.path.isfile(f))/(1024*1024))


0

Этот скрипт сообщает вам, какой файл является самым большим в CWD, а также сообщает, в какой папке находится файл. Этот скрипт у меня работает на win8 и python 3.3.3 shell

import os

folder=os.cwd()

number=0
string=""

for root, dirs, files in os.walk(folder):
    for file in files:
        pathname=os.path.join(root,file)
##        print (pathname)
##        print (os.path.getsize(pathname)/1024/1024)
        if number < os.path.getsize(pathname):
            number = os.path.getsize(pathname)
            string=pathname


##        print ()


print (string)
print ()
print (number)
print ("Number in bytes")

0

По общему признанию, это отчасти хакерское и работает только на Unix / Linux.

Это соответствует, du -sb .потому что в действительности это оболочка Python bash, которая запускает du -sb .команду.

import subprocess

def system_command(cmd):
    """"Function executes cmd parameter as a bash command."""
    p = subprocess.Popen(cmd,
                         stdout=subprocess.PIPE,
                         stderr=subprocess.PIPE,
                         shell=True)
    stdout, stderr = p.communicate()
    return stdout, stderr

size = int(system_command('du -sb . ')[0].split()[0])

0

Я немного опоздал (и новичок) здесь, но я решил использовать модуль подпроцесса и командную строку 'du' в Linux, чтобы получить точное значение размера папки в МБ. Мне пришлось использовать if и elif для корневой папки, потому что в противном случае подпроцесс вызывает ошибку из-за ненулевого возвращаемого значения.

import subprocess
import os

#
# get folder size
#
def get_size(self, path):
    if os.path.exists(path) and path != '/':
        cmd = str(subprocess.check_output(['sudo', 'du', '-s', path])).\
            replace('b\'', '').replace('\'', '').split('\\t')[0]
        return float(cmd) / 1000000
    elif os.path.exists(path) and path == '/':
        cmd = str(subprocess.getoutput(['sudo du -s /'])). \
            replace('b\'', '').replace('\'', '').split('\n')
        val = cmd[len(cmd) - 1].replace('/', '').replace(' ', '')
        return float(val) / 1000000
    else: raise ValueError

0

Получить размер каталога

Свойства раствора:

  • возвращает оба: видимый размер (количество байтов в файле) и фактическое дисковое пространство, используемое файлами.
  • считает жестко связанные файлы только один раз
  • подсчитывает символические ссылки таким же образом du делает
  • не использует рекурсию
  • использует st.st_blocksдля используемого дискового пространства, таким образом, работает только на Unix-подобных системах

Код:

import os


def du(path):
    if os.path.islink(path):
        return (os.lstat(path).st_size, 0)
    if os.path.isfile(path):
        st = os.lstat(path)
        return (st.st_size, st.st_blocks * 512)
    apparent_total_bytes = 0
    total_bytes = 0
    have = []
    for dirpath, dirnames, filenames in os.walk(path):
        apparent_total_bytes += os.lstat(dirpath).st_size
        total_bytes += os.lstat(dirpath).st_blocks * 512
        for f in filenames:
            fp = os.path.join(dirpath, f)
            if os.path.islink(fp):
                apparent_total_bytes += os.lstat(fp).st_size
                continue
            st = os.lstat(fp)
            if st.st_ino in have:
                continue  # skip hardlinks which were already counted
            have.append(st.st_ino)
            apparent_total_bytes += st.st_size
            total_bytes += st.st_blocks * 512
        for d in dirnames:
            dp = os.path.join(dirpath, d)
            if os.path.islink(dp):
                apparent_total_bytes += os.lstat(dp).st_size
    return (apparent_total_bytes, total_bytes)

Пример использования:

>>> du('/lib')
(236425839, 244363264)

$ du -sb /lib
236425839   /lib
$ du -sB1 /lib
244363264   /lib

Удобочитаемый размер файла

Свойства раствора:

Код:

def humanized_size(num, suffix='B', si=False):
    if si:
        units = ['','K','M','G','T','P','E','Z']
        last_unit = 'Y'
        div = 1000.0
    else:
        units = ['','Ki','Mi','Gi','Ti','Pi','Ei','Zi']
        last_unit = 'Yi'
        div = 1024.0
    for unit in units:
        if abs(num) < div:
            return "%3.1f%s%s" % (num, unit, suffix)
        num /= div
    return "%.1f%s%s" % (num, last_unit, suffix)

Пример использования:

>>> humanized_size(236425839)
'225.5MiB'
>>> humanized_size(236425839, si=True)
'236.4MB'
>>> humanized_size(236425839, si=True, suffix='')
'236.4M'

0

Решение, которое работает на Python 3.6 с использованием pathlib.

from pathlib import Path

sum([f.stat().st_size for f in Path("path").glob("**/*")])

0

Рекурсивная папка / размер файла Python 3.6+ с использованием os.scandir. Как мощный , как в ответ по @blakev, но короче и в ЭСПЦ стиле питона .

import os

def size(path, *, follow_symlinks=False):
    try:
        with os.scandir(path) as it:
            return sum(size(entry, follow_symlinks=follow_symlinks) for entry in it)
    except NotADirectoryError:
        return os.stat(path, follow_symlinks=follow_symlinks).st_size

0
def recursive_dir_size(path):
    size = 0

    for x in os.listdir(path):
        if not os.path.isdir(os.path.join(path,x)):
            size += os.stat(os.path.join(path,x)).st_size
        else:
            size += recursive_dir_size(os.path.join(path,x))

    return size

Я написал эту функцию, которая дает мне точный общий размер каталога, я пробовал другие решения для циклов с os.walk, но я не знаю, почему конечный результат всегда был меньше, чем фактический размер (в Ubuntu 18 env). Должно быть, я сделал что-то не так, но кого это волнует, написал, что этот работает отлично.

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.