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.
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 walk
método más eficiente proporcionado por el scandir
paquete de terceros . En Python 3.5 y versiones posteriores, este paquete se ha incorporado a la biblioteca estándar y os.walk
ha recibido el aumento correspondiente en el rendimiento.
Actualización 2019
Recientemente he estado usando pathlib
más y más, aquí hay una pathlib
solución:
from pathlib import Path
root_directory = Path('.')
sum(f.stat().st_size for f in root_directory.glob('**/*') if f.is_file())
st_size
si no desea seguir los enlaces simbólicos, como debe usar lstat
.
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 print
en la última línea, funcionará para las versiones actuales de python2
y 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
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("."))
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
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.
sum(entry.stat().st_size for entry in os.scandir(file))
. No hay razón para hacer una lista, porque también sum
toma iteradores.
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
lstat
.
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()
os.lstat
(en lugar de os.stat
), lo que evita los siguientes enlaces simbólicos: docs.python.org/2/library/os.html#os.lstat
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
df -sb
.
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))])
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])
Usando pathlib
me 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.
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.
os.walk
para verificar el tamaño de la subcarpeta de forma recursiva?
One-liner dices ... Aquí hay un one liner:
sum([sum(map(lambda fname: os.path.getsize(os.path.join(directory, fname)), files)) for directory, folders, files in os.walk(path)])
Aunque probablemente lo dividiría y no realiza comprobaciones.
Para convertir a kb, consulte Biblioteca reutilizable para obtener una versión legible para humanos del tamaño del archivo. y trabajarlo en
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 iglob
tiene 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'
glob
admite la recursividad. Puede usar:glob.glob('/var/**', recursive=True)
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
use la biblioteca sh : el módulo lo du
hace:
pip install sh
import sh
print( sh.du("-s", ".") )
91154728 .
si desea pasar asterix, use glob
como 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
para obtener el tamaño de un archivo, hay os.path.getsize ()
>>> import os
>>> os.path.getsize("/path/file")
35L
se informa en bytes.
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.
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
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
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
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))
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))
para python3.5 +
from pathlib import Path
def get_size(path):
return sum(p.stat().st_size for p in Path(path).rglob('*'))
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")
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])
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
Propiedades de la solución:
du
lo hacest.st_blocks
para el espacio en disco utilizado, por lo tanto funciona solo en sistemas tipo UnixEl 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
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'
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("**/*")])
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
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.
tree
comando en los sistemas * nix hace todo esto de forma gratuita.tree -h -d --du /path/to/dir
.du -sh /path/to/dir/*