Avant de réinventer cette roue, quelqu'un a-t-il une routine Nice pour calculer la taille d'un répertoire à l'aide de Python? Ce serait très bien si la routine formaterait bien la taille en Mo/Go, etc.
Ceci saisit les sous-répertoires:
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)
total_size += os.path.getsize(fp)
return total_size
print get_size()
Et un jeu de société amusant avec os.listdir (n'inclut pas les sous-répertoires):
import os
sum(os.path.getsize(f) for f in os.listdir('.') if os.path.isfile(f))
Référence:
os.path.getsize - Donne la taille en octets
Updated Pour utiliser os.path.getsize, cela est plus clair que d'utiliser la méthode os.stat (). St_size.
_ {Merci à ghostdog74 pour l'avoir signalé!} _
os.stat - st_size Donne la taille en octets. Peut également être utilisé pour obtenir la taille de fichier et d’autres informations relatives aux fichiers.
Mise à jour 2018
Si vous utilisez Python 3.4 ou version antérieure, vous pouvez envisager d'utiliser la méthode plus efficace walk
fournie par le tiers scandir
package. Dans Python 3.5 et versions ultérieures, ce package a été intégré à la bibliothèque standard et os.walk
a bénéficié de l'augmentation correspondante des performances.
Certaines des approches suggérées jusqu'à présent implémentent une récursion, d'autres utilisent un Shell ou ne produiront pas de résultats parfaitement formatés. Lorsque votre code est ponctuel pour les plates-formes Linux, vous pouvez obtenir le formatage habituel, récursivité incluse, en une couche. À l'exception de la print
dans la dernière ligne, cela fonctionnera pour les versions actuelles de python2
et 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 __== "__main__":
print(du('.'))
est simple, efficace et fonctionnera pour les fichiers et les répertoires multiniveaux:
$ chmod 750 du.py
$ ./du.py
2,9M
Un peu tard après 5 ans, mais comme cela figure toujours dans les listes de recherche des moteurs de recherche, cela pourrait être utile ...
Voici une fonction récursive (elle récapitule de manière récursive la taille de tous les sous-dossiers et de leurs fichiers respectifs) qui renvoie exactement les mêmes octets que lors de l'exécution de "du -sb". sous linux (où "." signifie "le dossier actuel"):
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("."))
Taille de dossier récursive Python 3.5 utilisant 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
la réponse de monknut est bonne mais elle échoue sur un lien symbolique brisé, vous devez donc également vérifier si ce chemin existe vraiment
if os.path.exists(fp):
total_size += os.stat(fp).st_size
La réponse acceptée ne prend pas en compte les liens physiques ou matériels et compte ces fichiers deux fois. Vous voudriez garder trace des inodes que vous avez vus, et ne pas ajouter la taille de ces fichiers.
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()
La réponse de Chris est bonne, mais pourrait être rendue plus idiomatique en utilisant un ensemble pour vérifier les répertoires vus, ce qui évite également l'utilisation d'une exception pour le contrôle:
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
un one-liner récursif:
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))])
Pour la deuxième partie de la question
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])
Vous pouvez faire quelque chose comme ça:
import commands
size = commands.getoutput('du -sh /path/').split()[0]
dans ce cas, je n'ai pas testé le résultat avant de le renvoyer. Si vous le souhaitez, vous pouvez le vérifier avec commands.getstatusoutput.
Un peu tard dans la soirée mais dans une ligne à condition que vous ayez glob2 et humanize installé. Notez que dans Python 3, la valeur par défaut iglob
a un mode récursif. Comment modifier le code pour Python 3 est laissé comme un exercice trivial pour le lecteur.
>>> import os
>>> from humanize import naturalsize
>>> from glob2 import iglob
>>> naturalsize(sum(os.path.getsize(x) for x in iglob('/var/**'))))
'546.2 MB'
One-Liner, dites-vous ... Voici 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)])
Bien que je le séparerais probablement et qu’il n’effectue aucun contrôle.
Pour convertir en ko voir Bibliothèque réutilisable pour obtenir une version lisible par l'homme de la taille du fichier? et ça marche dedans
C'est pratique:
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
Le script suivant imprime la taille du répertoire de tous les sous-répertoires du répertoire spécifié. Il essaie également de tirer parti (si possible) de la mise en cache des appels de fonctions récursives. Si un argument est omis, le script fonctionnera dans le répertoire en cours. La sortie est triée par la taille du répertoire, du plus grand au plus petit. Vous pouvez donc l'adapter à vos besoins.
PS j’ai utilisé la recette 578019 pour afficher la taille du répertoire au format convivial ( 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 __== '__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())
Exemple de sortie:
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: déplacé null_decorator ci-dessus, comme utilisateur 2233949 recommandé
utiliser la bibliothèque sh : le module du
le fait:
pip install sh
import sh
print( sh.du("-s", ".") )
91154728 .
si vous voulez passer astérisque, utilisez glob
comme décrit ici .
pour convertir les valeurs en valeurs lisibles, utilisez humanize :
pip install humanize
import humanize
print( humanize.naturalsize( 91157384 ) )
91.2 MB
pour obtenir la taille d'un fichier, il y a os.path.getsize ()
>>> import os
>>> os.path.getsize("/path/file")
35L
son rapporté en octets.
Lorsque la taille des sous-répertoires est calculée, il convient de mettre à jour la taille du dossier de son parent, jusqu'à ce qu'il atteigne le parent racine.
La fonction suivante calcule la taille du dossier et de tous ses sous-dossiers.
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
J'utilise python 2.7.13 avec scandir et voici ma fonction récursive à une ligne pour obtenir la taille totale d'un dossier:
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
Si vous êtes sous Windows, vous pouvez faire:
installez le module pywin32 en lançant:
pip installer pywin32
puis en codant ce qui suit:
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))
Voici une couche qui le fait récursivement (option récursive disponible à 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))
Une solution qui fonctionne sur Python 3.6 en utilisant pathlib.
from pathlib import Path
sum([f.stat().st_size for f in Path("path").glob("**/*")])
En utilisant pathlib
, je suis arrivé à cette ligne pour obtenir la taille d'un dossier:
sum(file.stat().st_size for file in Path(folder).rglob('*'))
Et voici ce que j'ai proposé pour une sortie bien formatée:
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))
Usage:
>>> 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)
Je suis également tombé sur cette question , qui propose des stratégies plus compactes et probablement plus performantes.
Ce script vous indique le fichier le plus volumineux dans le fichier CWD et vous indique également dans quel dossier il se trouve .. Ce script fonctionne pour moi sur win8 et 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")
Pour ce que ça vaut ... la commande de l'arbre fait tout cela gratuitement:
tree -h --du /path/to/dir # files and dirs
tree -h -d --du /path/to/dir # dirs only
J'adore Python, mais de loin la solution la plus simple au problème ne nécessite aucun nouveau code.
pour python3.5 +
from pathlib import Path
def get_size(path):
return sum(p.stat().st_size for p in Path(path).rglob('*'))
Je suis un peu en retard (et nouveau) ici, mais j'ai choisi d'utiliser le module de sous-processus et la ligne de commande «du» avec Linux pour récupérer une valeur précise de la taille du dossier en Mo. Je devais utiliser if et Elif pour le dossier racine, sinon le sous-processus soulève une erreur en raison d'une valeur non nulle renvoyée.
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
Il est vrai que c’est un peu féroce et ne fonctionne que sous Unix/Linux.
Il correspond à du -sb .
car il s'agit en réalité d'un wrapper Python bash qui exécute la commande du -sb .
.
import subprocess
def system_command(cmd):
""""Function executes cmd parameter as a bash command."""
p = subprocess.Popen(cmd,
stdout=subprocess.PIPE,
stderr=subprocess.PIPE,
Shell=True)
stdout, stderr = p.communicate()
return stdout, stderr
size = int(system_command('du -sb . ')[0].split()[0])
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
J'ai écrit cette fonction qui me donne la taille globale exacte d'un répertoire, j'ai essayé d'autres solutions pour les boucles avec os.walk mais je ne sais pas pourquoi le résultat final était toujours inférieur à la taille réelle (sur ubuntu 18 env). Je dois avoir fait quelque chose de mal, mais qui se soucie écrit que celui-ci fonctionne parfaitement bien.
Python 3.6 + taille de dossier/fichier récursive avec os.scandir
. Aussi puissant que dans réponse de @blakev, mais plus court et dans EAFP python style .
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
Propriétés de la solution:
du
st.st_blocks
pour l'espace disque utilisé, fonctionne donc uniquement sur les systèmes de type UnixLe code:
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)
Exemple d'utilisation:
>>> du('/lib')
(236425839, 244363264)
$ du -sb /lib
236425839 /lib
$ du -sB1 /lib
244363264 /lib
Propriétés de la solution:
Le code:
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)
Exemple d'utilisation:
>>> humanized_size(236425839)
'225.5MiB'
>>> humanized_size(236425839, si=True)
'236.4MB'
>>> humanized_size(236425839, si=True, suffix='')
'236.4M'