Obliczanie rozmiaru katalogu za pomocą Pythona?


181

Czy przed ponownym wynalezieniem tego konkretnego koła ktoś ma dobrą procedurę do obliczania rozmiaru katalogu za pomocą Pythona? Byłoby bardzo miło, gdyby procedura ładnie sformatowała rozmiar w Mb / Gb itp.


13
To NIE byłoby bardzo miłe. Powinieneś mieć jedną funkcję do obliczania rozmiaru i dość niezależną funkcję (która mogłaby być użyta również na przykład z rozmiarami pamięci) do „ładnego formatowania rozmiaru w Mb / Gb itp.”.
John Machin,

17
Tak, wiem, ale oszczędza to zadawania dwóch pytań.
Gary Willoughby,

1
treeKomenda na systemów uniksowych robi to wszystko za darmo. tree -h -d --du /path/to/dir.
meh,

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

Odpowiedzi:


251

Przechodzi wszystkie podkatalogi; sumowanie rozmiarów plików:

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

I oneliner dla zabawy przy użyciu os.listdir ( nie obejmuje podkatalogów ):

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

Odniesienie:

Zaktualizowany Aby użyć os.path.getsize , jest to wyraźniejsze niż użycie metody os.stat (). St_size.

Dzięki ghostdog74 za zwrócenie na to uwagi!

os.stat - st_size podaje rozmiar w bajtach. Może być również użyty do uzyskania rozmiaru pliku i innych informacji związanych z plikiem.

import os

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

Aktualizacja 2018

Jeśli używasz Python 3.4 lub wcześniejszego, możesz rozważyć użycie bardziej wydajnej walkmetody dostarczonej przez scandirpakiet innej firmy . W Pythonie 3.5 i nowszych pakiet ten został włączony do standardowej biblioteki ios.walk uzyskał odpowiedni wzrost wydajności.

Aktualizacja 2019

Ostatnio używam pathlibcoraz więcej, oto pathlibrozwiązanie:

from pathlib import Path

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

14
+1, ale oneliner nie zwraca poprawnego wyniku, ponieważ nie jest rekurencyjny
luc

2
Tak, to tylko dla płaskiej skrzynki katalogowej.
monkut

35
Dla prawdziwej zabawy możesz zrobić rozmiar rekurencyjny w jednym wierszu: suma (os.path.getsize (os.path.join (dirpath, nazwa pliku)) dla dirpath, dirnames, nazwy plików w os.walk (PATH) dla nazwy pliku w nazwach plików)
driax,

2
Ale musisz użyć, st_sizejeśli nie chcesz podążać za dowiązaniami symbolicznymi, jak powinieneś wtedy użyć lstat.
asmeurer

3
Ostrzeżenie! to nie to samo co „du -sb”. Zobacz odpowiedź Samuela Lampa! Twój kod ignoruje rozmiar folderu używanego do przechowywania FAT.
Yauhen Yakimovich

43

Niektóre z sugerowanych do tej pory podejść wdrażają rekurencję, inne wykorzystują powłokę lub nie dają dobrze sformatowanych wyników. Jeśli Twój kod jest jednorazowy dla platform Linux, możesz uzyskać formatowanie w zwykły sposób, łącznie z rekurencją, jako jeden wiersz. Z wyjątkiem printostatniego wiersza, będzie działać dla bieżących wersji python2i 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('.'))

jest prosty, wydajny i będzie działał dla plików i katalogów wielopoziomowych:

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

13
Uwaga Tylko Linux.
meawoppl

15
Python, będąc z natury wieloplatformowym, powinien prawdopodobnie unikać tego
Jonathan

11
Dziękuję za te uwagi. Dodałem pewne zastrzeżenie dotyczące zależności platformy od odpowiedzi. Jednak znaczna część kodu Python, jeśli jednorazowe skrypty. Taki kod nie powinien mieć ograniczeń funkcjonalnych, długich i podatnych na błędy przejść ani nietypowych wyników w przypadkach skrajnych, tylko ze względu na przenośność ponad wszelką potrzebę . Jak zawsze jest to kompromis, a do dewelopera należy wybór mądrze;)
flaschbier

9
Nitpick: nie Linux, ale Unix / Posix :)
Pan Shark

3
Prawdopodobnie rozsądnie jest dodać opcję -x do polecenia du, aby ograniczyć wyszukiwanie do systemu plików. Innymi słowy, zamiast tego użyj [„du”, „-shx”, path].
Keith Hanlan

24

Oto funkcja rekurencyjna (rekurencyjnie sumuje rozmiar wszystkich podfolderów i odpowiadających im plików), która zwraca dokładnie takie same bajty, jak przy uruchomieniu „du -sb”. w systemie Linux (gdzie „.” oznacza „bieżący folder”):

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
Ta funkcja oblicza również rozmiar dowiązania symbolicznego - jeśli chcesz pominąć dowiązania symboliczne, musisz sprawdzić, że to nie to: jeśli os.path.isfile (itempath) i os.path.islink (itempath) i elif os.path.isdir ( itempath) i os.path.islink (itempath).
lot między

17

Rozmiar folderu rekurencyjnego w Pythonie 3.5 przy użyciu 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
Metoda jednowierszowa Python 3, jeśli nie martwi się o rekurencyjność sum([entry.stat().st_size for entry in os.scandir(file)]). Uwaga dane wyjściowe są w bajtach, / 1024, aby uzyskać KB, i / (1024 * 1024), aby uzyskać MB.
weiji14

4
@ weiji14 Zgubić nawiasy, tzn sum(entry.stat().st_size for entry in os.scandir(file)). Nie ma powodu do tworzenia listy, ponieważ sumwymaga iteracji.
Vedran Šego

8

odpowiedź monknut jest dobra, ale nie działa na zepsutym dowiązaniu symbolicznym, więc musisz również sprawdzić, czy ta ścieżka naprawdę istnieje

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

3
Prawdopodobnie nie chcesz podążać za dowiązaniami symbolicznymi. Powinieneś użyć lstat.
asmeurer

8

Akceptowana odpowiedź nie uwzględnia twardych ani miękkich linków i liczy te pliki dwa razy. Chcesz śledzić, które i-węzły widziałeś, i nie dodawać rozmiaru tych plików.

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
Rozważ użycie os.lstat(zamiast os.stat), co pozwala uniknąć następujących dowiązań symbolicznych: docs.python.org/2/library/os.html#os.lstat
Peter Briggs

7

Odpowiedź Chrisa jest dobra, ale można ją uczynić bardziej idiomatyczną, używając zestawu do sprawdzania widocznych katalogów, co również pozwala uniknąć wyjątku dla przepływu sterowania:

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
Odpowiedź Chrisa również nie bierze pod uwagę dowiązań symbolicznych ani rozmiarów samych katalogów. Odpowiednio zredagowałem twoją odpowiedź, wyjście stałej funkcji jest teraz identyczne z df -sb.
Creshal,

7

rekurencyjny jednowarstwowy:

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
Ale to nie jest jeden liniowiec. Jednak oblicza rekurencyjnie rozmiar folderu (nawet jeśli folder ma wiele folderów w środku) w bajtach i podaje prawidłową wartość.
Venkatesh,

Poszedłem do tego jako łatwy w użyciu i pracowałem po raz pierwszy w systemie Windows
hum3,

5

Do drugiej części pytania

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

Używając pathlibI wymyśliłem ten jeden wiersz, aby uzyskać rozmiar folderu:

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

Oto, co wymyśliłem dla ładnie sformatowanego wyjścia:

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

Stosowanie:

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

Natknąłem się również na to pytanie , które ma bardziej zwarte i prawdopodobnie bardziej wydajne strategie drukowania rozmiarów plików.


4

Możesz zrobić coś takiego:

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

w tym przypadku nie przetestowałem wyniku przed jego zwróceniem, jeśli chcesz, możesz to sprawdzić za pomocą polecenia .getstatusoutput.


Jaka jest wydajność w porównaniu do wykorzystania os.walkdo rekurencyjnego sprawdzania rozmiaru podfolderu?
TomSawyer


4

Trochę późno na imprezę, ale w jednym wierszu, pod warunkiem, że masz zainstalowany glob2 i humanizację . Zauważ, że w Pythonie 3 domyślnie iglobma tryb rekurencyjny. Jak zmodyfikować kod dla Pythona 3 jest dla czytelnika trywialnym ćwiczeniem.

>>> 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
Począwszy od Python 3.5 wbudowane globobsługuje rekurencję. Możesz użyć:glob.glob('/var/**', recursive=True)
adzenith

3

Poniższy skrypt drukuje rozmiar katalogu wszystkich podkatalogów dla określonego katalogu. Próbuje również skorzystać (jeśli to możliwe) z buforowania wywołań funkcji rekurencyjnych. Jeśli argument zostanie pominięty, skrypt będzie działał w bieżącym katalogu. Dane wyjściowe są sortowane według wielkości katalogu od największych do najmniejszych. Możesz więc dostosować go do swoich potrzeb.

PS Użyłem przepisu 578019 do wyświetlania rozmiaru katalogu w formacie przyjaznym dla ludzi ( 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())

Przykładowe dane wyjściowe:

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)

EDYCJA: przeniesiono null_decorator powyżej, zgodnie z zaleceniem user2233949


Twój skrypt działa dobrze, ale musisz przenieść funkcję null_decorator nad wiersz „if sys.version_info> = ...”. W przeciwnym razie otrzymasz „null_decorator” nie jest zdefiniowanym wyjątkiem. Ale potem działa świetnie.
user2233949

@ user2233949, dziękuję! Odpowiednio zmodyfikowałem kod.
MaxU

3

użyj biblioteki sh : moduł duto robi:

pip install sh

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

jeśli chcesz przekazać gwiazdkę, użyj globzgodnie z opisem tutaj .

aby przekonwertować wartości na czytelne dla ludzi, użyj humanize :

pip install humanize

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

2

Aby uzyskać rozmiar jednego pliku, istnieje os.path.getsize ()

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

jest zgłaszany w bajtach.


2

Za co warto ... polecenie drzewa robi to wszystko za darmo:

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

Uwielbiam Python, ale zdecydowanie najprostsze rozwiązanie problemu nie wymaga nowego kodu.


@ Abdur-RahmaanJanhangeer, to prawda. To prawda.
meh

2

Jest to przydatne:

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

Używam Pythona w wersji 2.7.13 ze scandir i oto moja rekurencyjna funkcja jednoliniowa, aby uzyskać całkowity rozmiar folderu:

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

Gdy obliczany jest rozmiar podkatalogów, powinien zaktualizować rozmiar folderu nadrzędnego, a to będzie trwać, dopóki nie dotrze do nadrzędnego katalogu głównego.

Poniższa funkcja oblicza rozmiar folderu i wszystkich jego podfolderów.

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

Jeśli korzystasz z systemu operacyjnego Windows, możesz:

zainstaluj moduł pywin32, uruchamiając:

pip install pywin32

a następnie koduje następujące elementy:

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

Oto jedna linijka, która robi to rekurencyjnie (opcja rekurencyjna dostępna od wersji 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))

1

dla python3.5 +

from pathlib import Path

def get_size(path):
    return sum(p.stat().st_size for p in Path(path).rglob('*'))

0

Ten skrypt informuje, który plik jest największy na CWD, a także informuje, w którym folderze znajduje się ten plik. Ten skrypt działa dla mnie na powłoce win8 i 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

Trzeba przyznać, że jest to dość hackerskie i działa tylko w systemach Unix / Linux.

Pasuje, du -sb .ponieważ w efekcie jest to opakowanie bash w języku Python, które uruchamia du -sb .polecenie.

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

Jestem trochę spóźniony (i nowy) tutaj, ale zdecydowałem się użyć modułu podprocesu i wiersza poleceń „du” w systemie Linux, aby uzyskać dokładną wartość rozmiaru folderu w MB. Musiałem użyć if i elif do folderu głównego, ponieważ w przeciwnym razie podproces podnosi błąd z powodu zwrócenia niezerowej wartości.

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

Uzyskaj rozmiar katalogu

Właściwości rozwiązania:

  • zwraca zarówno: pozorny rozmiar (liczbę bajtów w pliku), jak i rzeczywiste miejsce na dysku, z którego korzystają pliki.
  • zlicza połączone pliki tylko raz
  • zlicza dowiązania symboliczne w ten sam sposób du robi
  • nie używa rekurencji
  • wykorzystuje miejsce st.st_blocksna dysku, dlatego działa tylko w systemach uniksopodobnych

Kod:

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)

Przykładowe użycie:

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

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

Rozmiar pliku czytelny dla człowieka

Właściwości rozwiązania:

Kod:

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)

Przykładowe użycie:

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

0

Rozwiązanie działające w Pythonie 3.6 przy użyciu pathlib.

from pathlib import Path

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

0

Python 3.6+ rekurencyjny rozmiar folderu / pliku przy użyciu os.scandir. Tak potężne, jak w odpowiedzi przez @blakev, ale krótszy i EAFP stylu Pythona .

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

Napisałem tę funkcję, która daje mi dokładny ogólny rozmiar katalogu, próbowałem innych rozwiązań pętli z os.walk, ale nie wiem, dlaczego wynik końcowy był zawsze mniejszy niż rzeczywisty rozmiar (na Ubuntu 18 env). Musiałem zrobić coś złego, ale kogo to obchodzi, ten napisał doskonale.

Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.