Обчислення розміру каталогу за допомогою Python?


181

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


13
Було б НЕ дуже приємно. У вас повинна бути одна функція для обчислення розміру і цілком незалежна функція (яка може бути використана, наприклад, з розмірами пам'яті), щоб "добре форматувати розмір у Мб / Гб тощо".
Джон Махін

17
Так, я знаю, але це економить, задаючи два питання.
Gary Willoughby

1
treeКоманда на * NIX систем робить все це безкоштовно. tree -h -d --du /path/to/dir.
meh

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

Відповіді:


251

Це охоплює всі підкаталоги; підсумовування розмірів файлів:

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, ім'я файлу)) для dirpath, dirname, назви файлів у os.walk (PATH) для імені файлу у назви файлів)
driax

2
Але ви повинні користуватися, st_sizeякщо не хочете слідувати посиланнями, як слід використовувати lstat.
асмеурер

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
Nb. Лише 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
Ця функція також обчислює розмір символьної посилання - якщо ви хочете пропустити символьні посилання, ви повинні перевірити, що це не так: якщо 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.
асмеурер

8

Прийнята відповідь не враховує жорсткі або м'які посилання, і буде рахувати ці файли двічі. Ви хочете відслідковувати, які саме коди ви бачили, а не додавати розмір для цих файлів.

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.
Крешал

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
Хоча це не один лайнер. Однак він обчислює рекурсивно розмір папки (навіть якщо папка має кілька папок всередині) у байтах і дає правильне значення.
Венкатеш

Я пішов за цим як простий у використанні і вперше працював у Windows
hum3

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)])

Хоча я б, мабуть, розділив це, і він не перевіряє.

Для перетворення в kb див. Бібліотеку багаторазового використання, щоб отримати читану людиною версію розміру файлу? і працюйте над цим


4

Трохи запізнюємось на вечірку, але в одному рядку за умови встановлення glob2 та гуманізації . Зауважте, що в 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)

EDIT: переміщено null_decorator вгорі, як рекомендує user2233949


Ваш сценарій працює добре, але вам потрібно перемістити функцію null_decorator над рядком 'if sys.version_info> = ...'. Інакше ви отримаєте "null_decorator" не визначено винятком. Хоча після цього чудово працює.
користувач2233949

@ user2233949, дякую! Я відповідно змінив код.
МаксУ

3

використовувати бібліотеку sh : модуль duробить це:

pip install sh

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

якщо ви хочете передати астерикс, використовуйте, globяк описано тут .

для перетворення значень у читабельні людиною використовуйте гуманізацію :

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, це правда. Це правда.
meh

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 зі скандіром, і ось моя рекурсивна функція з одним лайнером, щоб отримати загальний розмір папки:

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 встановити 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

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, яка виконує 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 для папок root, оскільки в іншому випадку підпроцес викликає помилку через повернене ненульове значення.

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+ за допомогою використання os.scandir. Настільки потужний, як у відповіді @blakev, але коротший і в стилі EAFP python .

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.