¿Calcular el tamaño de un directorio usando Python?


182

Antes de reinventar esta rueda en particular, ¿alguien tiene una buena rutina para calcular el tamaño de un directorio usando Python? Sería muy bueno si la rutina formateara bien el tamaño en Mb / Gb, etc.


13
NO sería muy lindo. Debería tener una función para calcular el tamaño y una función bastante independiente (que podría usarse también con tamaños de memoria, por ejemplo) para "formatear bien el tamaño en Mb / Gb, etc.".
John Machin

17
Sí, lo sé, pero esto ahorra haciendo dos preguntas.
Gary Willoughby

1
El treecomando en los sistemas * nix hace todo esto de forma gratuita. tree -h -d --du /path/to/dir.
meh

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

Respuestas:


252

Esto recorre todos los subdirectorios; sumando tamaños de archivo:

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

Y una línea para divertirse usando os.listdir ( no incluye subdirectorios ):

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

Referencia:

Actualizado Para usar os.path.getsize , esto es más claro que usar el método os.stat (). St_size.

¡Gracias a ghostdog74 por señalar esto!

os.stat - st_size Da el tamaño en bytes. También se puede utilizar para obtener el tamaño del archivo y otra información relacionada con el archivo.

import os

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

Actualización 2018

Si usa Python 3.4 o anterior, entonces puede considerar usar el walkmétodo más eficiente proporcionado por el scandirpaquete de terceros . En Python 3.5 y versiones posteriores, este paquete se ha incorporado a la biblioteca estándar y os.walkha recibido el aumento correspondiente en el rendimiento.

Actualización 2019

Recientemente he estado usando pathlibmás y más, aquí hay una pathlibsolución:

from pathlib import Path

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


14
1 pero el oneliner no devuelve un resultado válido porque no es recursivo
luc

2
Sí, es solo para el caso del directorio plano.
monkut

35
Para una verdadera diversión, puede hacer un tamaño recursivo en una línea: sum (os.path.getsize (os.path.join (dirpath, filename)) para dirpath, dirnames, nombres de archivo en os.walk (PATH) para nombre de archivo en nombres de archivo)
driax

2
Pero debe usarlo st_sizesi no desea seguir los enlaces simbólicos, como debe usar lstat.
Asmeurer

3
¡Advertencia! Esto no es lo mismo que 'du -sb'. ¡Vea la respuesta de Samuel Lampa! Su código ignora el tamaño de la carpeta utilizada para almacenar FAT.
Yauhen Yakimovich

43

Algunos de los enfoques sugeridos hasta ahora implementan una recursión, otros emplean un shell o no producirán resultados con un formato claro. Cuando su código es único para las plataformas Linux, puede obtener el formato de la forma habitual, incluida la recursividad, como una sola línea. Excepto printen la última línea, funcionará para las versiones actuales de python2y 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('.'))

es simple, eficiente y funcionará para archivos y directorios multinivel:

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

13
Nótese bien. Solo Linux.
meawoppl

15
Python, siendo de naturaleza multiplataforma, probablemente debería rehuir esto
Jonathan

11
Gracias por estos comentarios. Agregué algunas advertencias sobre la dependencia de la plataforma a la respuesta. Sin embargo, gran parte del código de Python es una secuencia de comandos única. Tal código no debe venir con limitaciones funcionales, pasajes largos y propensos a errores, o resultados poco comunes en casos extremos, solo por una portabilidad más allá de cualquier necesidad . Es, como siempre, una compensación, y es responsabilidad del desarrollador elegir sabiamente;)
flaschbier

9
Nitpick: no Linux sino específico para Unix / Posix :)
Mr Shark

3
Probablemente sea aconsejable agregar la opción '-x' al comando du para limitar la búsqueda al sistema de archivos. En otras palabras, use ['du', '-shx', ruta] en su lugar.
Keith Hanlan

24

Aquí hay una función recursiva (resume recursivamente el tamaño de todas las subcarpetas y sus respectivos archivos) que devuelve exactamente los mismos bytes que cuando se ejecuta "du -sb". en linux (donde "." significa "la carpeta actual"):

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
Esta función también calcula el tamaño del enlace simbólico: si desea omitir los enlaces simbólicos, debe verificar que no sea eso: si os.path.isfile (itempath) y os.path.islink (itempath) y elif os.path.isdir ( itempath) y os.path.islink (itempath).
airween

17

Tamaño de carpeta recursiva de 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 de una línea de Python 3 si no le preocupa la recursividad sum([entry.stat().st_size for entry in os.scandir(file)]). La salida de la nota está en bytes, / 1024 para obtener KB y / (1024 * 1024) para obtener MB.
weiji14

44
@ weiji14 perder los soportes, es decir, sum(entry.stat().st_size for entry in os.scandir(file)). No hay razón para hacer una lista, porque también sumtoma iteradores.
Vedran Šego

8

La respuesta de monknut es buena, pero falla en el enlace simbólico roto, por lo que también debe verificar si esta ruta realmente existe

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

3
Probablemente no quieras seguir enlaces simbólicos. Debe utilizar lstat.
Asmeurer

8

La respuesta aceptada no tiene en cuenta los enlaces duros o blandos, y contaría esos archivos dos veces. Desea realizar un seguimiento de los inodos que ha visto y no agregar el tamaño de esos archivos.

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

55
Considere usar os.lstat(en lugar de os.stat), lo que evita los siguientes enlaces simbólicos: docs.python.org/2/library/os.html#os.lstat
Peter Briggs

7

La respuesta de Chris es buena, pero podría hacerse más idiomática usando un conjunto para verificar los directorios vistos, lo que también evita usar una excepción para el flujo de control:

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
La respuesta de Chris tampoco tiene en cuenta los enlaces simbólicos ni los tamaños de los directorios en sí. He editado su respuesta en consecuencia, la salida de la función fija ahora es idéntica a df -sb.
Creshal

7

una línea 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
Sin embargo, no es un trazador de líneas. Sin embargo, calcula recursivamente el tamaño de la carpeta (incluso si la carpeta tiene varias carpetas dentro) en bytes y da el valor correcto.
Venkatesh

Fui por esto tan fácil de usar y trabajé por primera vez en Windows
hum3

5

Para la segunda parte de la pregunta.

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 pathlibme apareció esta línea para obtener el tamaño de una carpeta:

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

Y esto es lo que se me ocurrió para una salida bien formateada:

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)

También me encontré con esta pregunta , que tiene algunas estrategias más compactas y probablemente más eficaces para imprimir tamaños de archivo.


4

Puedes hacer algo como esto:

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

en este caso no he probado el resultado antes de devolverlo, si lo desea puede verificarlo con command.getstatusoutput.


¿Cómo se compara el rendimiento con el uso os.walkpara verificar el tamaño de la subcarpeta de forma recursiva?
TomSawyer


4

Un poco más tarde a la fiesta, pero en una línea siempre y cuando tenga glob2 y humanizar instalado. Tenga en cuenta que en Python 3, el valor predeterminado iglobtiene un modo recursivo. Cómo modificar el código para Python 3 se deja como un ejercicio trivial para el lector.

>>> 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
Comenzando con Python 3.5, el incorporado globadmite la recursividad. Puede usar:glob.glob('/var/**', recursive=True)
adzenith

3

El siguiente script imprime el tamaño del directorio de todos los subdirectorios para el directorio especificado. También trata de beneficiarse (si es posible) del almacenamiento en caché de las llamadas de funciones recursivas. Si se omite un argumento, el script funcionará en el directorio actual. La salida se ordena por el tamaño del directorio de mayor a menor. Para que pueda adaptarlo a sus necesidades.

PD: he utilizado la receta 578019 para mostrar el tamaño del directorio en formato amigable para los 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())

Salida de muestra:

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)

EDITAR: movió null_decorator arriba, como recomienda user2233949


Su script funciona bien, pero necesita mover la función null_decorator sobre la línea 'if sys.version_info> = ...'. De lo contrario, obtendrá un 'null_decorator' no es una excepción definida. Sin embargo, funciona muy bien después de eso.
user2233949

@ user2233949, gracias! He modificado el código correspondientemente.
MaxU

3

use la biblioteca sh : el módulo lo duhace:

pip install sh

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

si desea pasar asterix, use globcomo se describe aquí .

Para convertir los valores en legibles para humanos, use humanize :

pip install humanize

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

2

para obtener el tamaño de un archivo, hay os.path.getsize ()

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

se informa en bytes.


2

Por lo que vale ... el comando del árbol hace todo esto gratis:

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

Me encanta Python, pero la solución más simple al problema no requiere un código nuevo.


@ Abdur-RahmaanJanhangeer, esto es cierto. Esto es verdad.
meh

2

Es ú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

Estoy usando python 2.7.13 con scandir y aquí está mi función recursiva de una línea para obtener el tamaño total de una carpeta:

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

Cuando se calcula el tamaño de los subdirectorios, debe actualizar el tamaño de la carpeta principal y esto continuará hasta que llegue al padre raíz.

La siguiente función calcula el tamaño de la carpeta y todas sus subcarpetas.

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

Si está en el sistema operativo Windows, puede hacer:

instale el módulo pywin32 iniciando:

pip install pywin32

y luego codificando lo siguiente:

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

Aquí hay una línea que lo hace de forma recursiva (opción recursiva disponible a partir de 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

Este script le dice qué archivo es el más grande en el CWD y también le dice en qué carpeta está el archivo. Este script funciona para mí en win8 y 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

Es cierto que esto es un poco hack y solo funciona en Unix / Linux.

Coincide du -sb .porque, en efecto, este es un contenedor de Python bash que ejecuta el 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

Llego un poco tarde (y nuevo) aquí, pero elegí usar el módulo de subproceso y la línea de comando 'du' con Linux para recuperar un valor preciso para el tamaño de la carpeta en MB. Tuve que usar if y elif para la carpeta raíz porque, de lo contrario, el subproceso genera un error debido al valor devuelto distinto de cero.

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

Obtener el tamaño del directorio

Propiedades de la solución:

  • devuelve ambos: el tamaño aparente (número de bytes en el archivo) y el espacio de disco real que usan los archivos.
  • cuenta archivos vinculados solo una vez
  • conteos de enlaces simbólicos de la misma manera dulo hace
  • no usa recursividad
  • utiliza st.st_blockspara el espacio en disco utilizado, por lo tanto funciona solo en sistemas tipo Unix

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

Ejemplo de uso:

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

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

Tamaño de archivo legible para humanos

Propiedades de la solución:

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

Ejemplo de uso:

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

0

Una solución que funciona en Python 3.6 usando pathlib.

from pathlib import Path

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

0

Python 3.6+ carpeta recursiva / tamaño de archivo usando os.scandir. Tan poderoso como en la respuesta de @blakev, pero más corto y en estilo 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

Escribí esta función que me da el tamaño general exacto de un directorio, probé otras soluciones de bucle con os.walk pero no sé por qué el resultado final siempre fue menor que el tamaño real (en ubuntu 18 env). Debo haber hecho algo mal, pero a quién le importa, este funciona perfectamente bien.

Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.