Calculando o tamanho de um diretório usando Python?


182

Antes de reinventar essa roda específica, alguém tem uma boa rotina para calcular o tamanho de um diretório usando Python? Seria muito bom se a rotina formatasse bem o tamanho em Mb / Gb etc.


13
NÃO seria muito bom. Você deve ter uma função para calcular o tamanho e uma função bastante independente (que pode ser usada também com tamanhos de memória, por exemplo) para "formatar o tamanho perfeitamente em Mb / Gb etc".
John Machin

17
Sim, eu sei, mas isso economiza fazendo duas perguntas.
Gary Willoughby

1
O treecomando nos sistemas * nix faz tudo isso de graça. tree -h -d --du /path/to/dir.
Me

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

Respostas:


252

Isso percorre todos os subdiretórios; somando tamanhos de arquivo:

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

E um oneliner para se divertir usando os.listdir ( não inclui subdiretórios ):

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

Referência:

Atualizado Para usar os.path.getsize , isso é mais claro do que usar o método os.stat (). St_size.

Obrigado a ghostdog74 por apontar isso!

os.stat - st_size Dá o tamanho em bytes. Também pode ser usado para obter o tamanho do arquivo e outras informações relacionadas ao arquivo.

import os

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

Atualização 2018

Se você usa o Python 3.4 ou anterior, pode considerar usar o walkmétodo mais eficiente fornecido pelo scandirpacote de terceiros . No Python 3.5 e posterior, este pacote foi incorporado à biblioteca padrão e os.walkrecebeu o aumento correspondente no desempenho.

Atualização 2019

Recentemente, tenho usado pathlibcada vez mais, eis uma pathlibsolução:

from pathlib import Path

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

14
+1 mas o oneliner não retorna um resultado válido porque não é recursiva
luc

2
Sim, é apenas para o caso do diretório plano.
monkut

35
Para diversão real, você pode criar um tamanho recursivo em uma linha: sum (os.path.getsize (os.path.join (caminho do caminho, nome do arquivo)) para o caminho do caminho, nomes de arquivos, nomes de arquivos em os.walk (PATH) para nomes de arquivos em nomes de arquivos)
Driax

2
Mas você deve usar st_sizese não quiser seguir os links simbólicos, como deve usar lstat.
asmeurer

3
Aviso! isso não é o mesmo que 'du -sb'. Veja a resposta de Samuel Lampa! Seu código ignora o tamanho da pasta usada para armazenar o FAT.
Yauhen Yakimovich

43

Algumas das abordagens sugeridas até o momento implementam uma recursão, outras empregam um shell ou não produzirão resultados bem formatados. Quando o seu código é único para plataformas Linux, você pode obter a formatação como de costume, incluindo a recursão, como uma linha. Exceto pela printúltima linha, ele funcionará para as versões atuais de python2e 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('.'))

é simples, eficiente e funcionará para arquivos e diretórios multiníveis:

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

13
Nb. Apenas Linux.
meawoppl

15
Python, sendo multi-plataforma na natureza, provavelmente deve coíbe de este
Jonathan

11
Obrigado por estas observações. Eu adicionei algumas ressalvas sobre a dependência da plataforma à resposta. No entanto, grande parte do código Python é um script único. Esse código não deve vir com limitações funcionais, passagens longas e propensas a erros ou resultados incomuns em casos extremos, apenas por uma portabilidade além de qualquer necessidade . É, como sempre, um trade-off, e é a responsabilidade do desenvolvedor para escolher com sabedoria;)
flaschbier

9
Nitpick: não Linux, mas Unix / POSIX específica :)
Sr. Tubarão

3
Provavelmente é aconselhável adicionar a opção '-x' ao comando du para limitar a pesquisa ao sistema de arquivos. Em outras palavras, use ['du', '-shx', path].
Keith Hanlan

24

Aqui está uma função recursiva (que recursivamente resume o tamanho de todas as subpastas e seus respectivos arquivos) que retorna exatamente os mesmos bytes que ao executar "du -sb". no linux (onde "." significa "a pasta atual"):

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
Essa função também calcula o tamanho do link simbólico - se você quiser pular os links simbólicos, verifique se não é isso: if os.path.isfile (itempath) e os.path.islink (itempath) e elif os.path.isdir ( itempath) e os.path.islink (itempath).
airween 23/08/15

17

Tamanho da pasta recursiva do Python 3.5 usando 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
Método one-liner do Python 3, se não estiver preocupado com a recursividade sum([entry.stat().st_size for entry in os.scandir(file)]). Observe que a saída está em bytes, / 1024 para obter KB e / (1024 * 1024) para obter MB.
weiji14

4
@ weiji14 Perca os suportes, ou seja sum(entry.stat().st_size for entry in os.scandir(file)),. Não há razão para fazer uma lista, porque também sumleva iteradores.
Vedran Šego

8

A resposta monknut é boa, mas falha no link simbólico quebrado, portanto você também deve verificar se esse caminho realmente existe

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

3
Você provavelmente não deseja seguir links simbólicos. Você deveria usar lstat.
asmeurer

8

A resposta aceita não leva em consideração os links físicos ou físicos e contaria esses arquivos duas vezes. Você gostaria de acompanhar quais inodes viu e não adicionar o tamanho desses arquivos.

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
Considere o uso os.lstat(em vez de os.stat), o que evita seguintes links simbólicos: docs.python.org/2/library/os.html#os.lstat
Peter Briggs

7

A resposta de Chris é boa, mas poderia ser mais idiomática usando um conjunto para verificar os diretórios vistos, o que também evita o uso de uma exceção para o fluxo de controle:

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
A resposta de Chris também não leva em consideração os links simbólicos nem o tamanho dos diretórios. Eu editei sua resposta de acordo, a saída da função fixa agora é idêntica a df -sb.
Creshal

7

uma linha recursiva:

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
Não é um forro embora. No entanto, calcula recursivamente o tamanho da pasta (mesmo que a pasta tenha várias pastas dentro) em bytes e fornece o valor correto.
Venkatesh

Fui para este tão fácil de usar e trabalhou primeira vez no Windows
hum3

5

Para a segunda parte da pergunta

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

Usando pathlibeu vim esta linha para obter o tamanho de uma pasta:

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

E é isso que eu criei para uma saída bem formatada:

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

Uso:

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

Também me deparei com essa pergunta , que possui estratégias mais compactas e provavelmente com melhor desempenho para imprimir tamanhos de arquivo.


4

Você pode fazer algo assim:

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

neste caso, não testei o resultado antes de devolvê-lo, se você quiser, pode verificá-lo com commands.getstatusoutput.


Como é o desempenho comparado ao uso os.walkpara verificar o tamanho da subpasta recursivamente?
TomSawyer


4

Um pouco tarde para a festa, mas em uma linha desde que você tenha glob2 e humanizar instalado. Observe que no Python 3, o padrão iglobpossui um modo recursivo. Como modificar o código do Python 3 é deixado como um exercício trivial para o leitor.

>>> 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
A partir do Python 3.5, o built-in globsuporta recursão. Você pode usar:glob.glob('/var/**', recursive=True)
adzenith

3

O script a seguir imprime o tamanho do diretório de todos os subdiretórios do diretório especificado. Ele também tenta se beneficiar (se possível) do armazenamento em cache das chamadas de funções recursivas. Se um argumento for omitido, o script funcionará no diretório atual. A saída é classificada pelo tamanho do diretório, do maior para o menor. Para que você possa adaptá-lo às suas necessidades.

PS: usei a receita 578019 para mostrar o tamanho do diretório em formato compatível com humanos ( 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())

Saída de amostra:

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: moveu null_decorator acima, como user2233949 recomendado


Seu script funciona bem, mas você precisa mover a função null_decorator acima da linha 'if sys.version_info> = ...'. Caso contrário, você receberá uma exceção 'null_decorator' não definida. Funciona muito bem depois disso.
precisa saber é o seguinte

@ user2233949, obrigado! Eu modifiquei o código correspondentemente.
MaxU

3

use library sh : o módulo dufaz isso:

pip install sh

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

se você deseja passar o asterix, use globcomo descrito aqui .

para converter os valores em legíveis humanas, use humanize :

pip install humanize

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

2

para obter o tamanho de um arquivo, existe os.path.getsize ()

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

é relatado em bytes.


2

Pelo que vale a pena ... o comando tree faz tudo isso de graça:

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

Eu amo Python, mas, de longe, a solução mais simples para o problema não requer código novo.


@ Abdur-RahmaanJanhangeer, isso é verdade. Isso é verdade.
meh

2

É útil:

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

Estou usando python 2.7.13 com scandir e aqui está minha função recursiva de uma linha para obter o tamanho total de uma pasta:

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

Quando o tamanho dos subdiretórios é calculado, ele deve atualizar o tamanho da pasta do pai e isso continuará até atingir o pai raiz.

A função a seguir calcula o tamanho da pasta e todas as suas subpastas.

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

Se você estiver no sistema operacional Windows, pode:

instale o módulo pywin32 iniciando:

pip install pywin32

e depois codificando o seguinte:

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

Aqui está um liner que faz isso recursivamente (opção recursiva disponível no 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

para python3.5 +

from pathlib import Path

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

0

Esse script informa qual arquivo é o maior no CWD e também indica em qual pasta o arquivo está. Este script funciona para mim no shell win8 e 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

É certo que isso é meio hackeado e só funciona no Unix / Linux.

Corresponde du -sb .porque, na verdade, é um wrapper do Python bash que executa o du -sb .comando.

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

Estou um pouco atrasado (e novo) aqui, mas optei por usar o módulo de subprocesso e a linha de comando 'du' com o Linux para recuperar um valor preciso para o tamanho da pasta em MB. Eu tive que usar if e elif para a pasta raiz porque, caso contrário, o subprocesso gera um erro devido ao valor diferente de zero retornado.

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

Obter tamanho do diretório

Propriedades da solução:

  • retorna: o tamanho aparente (número de bytes no arquivo) e o espaço em disco real que os arquivos usam.
  • conta arquivos com links físicos apenas uma vez
  • conta links simbólicos da mesma maneira duque
  • não usa recursão
  • usa st.st_blockspara o espaço em disco usado, portanto, funciona apenas em sistemas do tipo Unix

O código:

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)

Exemplo de uso:

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

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

Tamanho do arquivo legível por humanos

Propriedades da solução:

O código:

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)

Exemplo de uso:

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

0

Uma solução que funciona no Python 3.6 usando pathlib.

from pathlib import Path

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

0

Tamanho do arquivo / pasta recursiva do Python 3.6+ usando os.scandir. Tão poderoso quanto na resposta de @blakev, mas mais curto e no estilo python do EAFP .

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

Eu escrevi esta função que me fornece o tamanho total exato de um diretório, tentei outro para soluções de loop com os.walk, mas não sei por que o resultado final sempre foi menor que o tamanho real (no ubuntu 18 env). Eu devo ter feito algo errado, mas quem se importa escreveu este funciona perfeitamente bem.

Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.