Calculer la taille d'un répertoire en utilisant Python?

avant que je réinvente cette roue particulière, quelqu'un a-t-il une bonne routine pour calculer la taille d'un répertoire en utilisant Python? Il serait très agréable si la routine formatait la taille bien en Mb/Gb etc.

117
demandé sur MackM 2009-09-08 11:06:42

24 réponses

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 oneliner pour s'amuser 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.chemin.getsize - donne la taille en octets

os.promenade

mise à Jour Utiliser os.chemin.getsize , c'est plus clair que d'utiliser l'os.stat().méthode st_size.

merci à ghostdog74 de le souligner!

os.stat - st_size donne la taille en octets. Peut également être utilisé pour obtenir la taille du fichier et d'autres informations liées au fichier.

mise à Jour 2018

si vous utilisez Python 3.4 ou avant, vous pouvez envisager d'utiliser la méthode plus efficace walk fournie par le tiers scandir package. En Python 3.5 et plus tard, ce paquet a été incorporé dans la bibliothèque standard et os.walk a reçu l'augmentation correspondante de performance.

163
répondu monkut 2018-08-02 04:20:05

certaines des approches suggérées jusqu'à présent mettent en œuvre une récursion, d'autres emploient un shell ou ne produiront pas de résultats parfaitement formatés. Quand votre code est unique pour les plates-formes Linux, vous pouvez obtenir le formatage comme d'habitude, recursion incluse, comme une doublure unique. Sauf pour le print dans la dernière ligne, il 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 __name__ == "__main__":
    print(du('.'))

est simple, efficace et fonctionnera pour les fichiers et les répertoires à plusieurs niveaux:

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

un peu en retard après 5 ans, mais parce que c'est toujours dans les listes d'hitlérisme des moteurs de recherche, il pourrait être utile...

28
répondu flaschbier 2015-09-18 04:53:14

Voici une fonction récursive (elle résume récursivement 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 ."dans linux (où l' "."signifie le "dossier en cours"):

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("."))
22
répondu Samuel Lampa 2010-12-06 16:25:28

Python 3.5 Taille du dossier récursif en 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
13
répondu blakev 2016-05-21 21:01:22

la réponse de monknut est bonne mais elle échoue sur le lien symbolique cassé, donc vous devez aussi vérifier si ce chemin existe vraiment

if os.path.exists(fp):
    total_size += os.stat(fp).st_size
7
répondu troex 2010-02-12 06:02:33

la réponse acceptée ne prend pas en compte les liens durs ou mous, et compterait ces fichiers deux fois. Vous voudriez garder la trace des inodes que vous avez vu, et ne pas ajouter la taille pour ces dossiers.

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()
7
répondu Chris 2012-10-20 02:18:48

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 d'utiliser une exception pour le flux de 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
7
répondu andrewh 2013-07-30 01:09:50

récursive de one-liner:

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))])
6
répondu 2013-09-12 11:58:01

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])
5
répondu Aurélien Ooms 2014-09-04 13:01:07

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 retourner, si vous le souhaitez, vous pouvez vérifier avec les commandes.getstatusoutput.

4
répondu Ali SAID OMAR 2013-08-04 00:44:53

une doublure, dites-vous... Voici une doublure:

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 l'aurais probablement divisé et il n'effectue pas de vérifications.

pour convertir en kb voir bibliothèque réutilisable pour obtenir une version lisible par l'homme de la taille du fichier? et le travailler en

3
répondu Martyn Bristow 2017-05-23 12:03:02

un peu en retard à la partie mais en une ligne à condition que vous ayez glob2 et humaniser 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'
3
répondu Sardathrion 2016-09-21 11:32:50

le script suivant imprime la taille du répertoire de tous les sous-répertoires pour le répertoire spécifié. Il essaie également de profiter (si possible) de la mise en cache des appels d'une fonction récursive. Si un argument est omis, le script fonctionnera dans le répertoire courant. La sortie est triée par la taille du répertoire des plus grands aux plus petits. De sorte que vous pouvez l'adapter à vos besoins.

PS j'ai utilisé la recette 578019 pour afficher la taille du répertoire dans un 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 __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())

sortie de L'échantillon:

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)

modifier: null_décorator déplacé ci-dessus, comme user2233949 recommandé

2
répondu MaxU 2016-02-02 23:35:12

utilisation de la bibliothèque sh : le module du :

pip install sh

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

si vous voulez passer Astérix, utilisez glob comme décrit ici .

pour convertir les valeurs en lisibles par l'homme, utilisez humaniser :

pip install humanize

import humanize
print( humanize.naturalsize( 91157384 ) )
91.2 MB
2
répondu Chris 2017-08-26 11:23:23

pour obtenir la taille d'un fichier, il y a os.chemin.getsize ()

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

sa en octets.

1
répondu ghostdog74 2009-11-21 23:57:12

si vous êtes dans Windows OS vous pouvez faire:

installer le module pywin32 en lançant:

pip install pywin32

et codant ensuite 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))
1
répondu BR1COP 2018-08-23 11:21:52

Il est à portée de main:

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
répondu Jundullah 2018-09-29 21:29:02

ce script vous indique quel fichier est le plus grand dans le CWD et vous indique également dans quel dossier le fichier est. 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")
0
répondu user3762880 2014-06-21 12:56:07

certes, il s'agit d'une sorte de hackish et ne fonctionne que sur Unix/Linux.

correspond à du -sb . car il s'agit en fait d'un enveloppeur 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])
0
répondu alfonso 2017-03-08 22:24:24

j'utilise python 2.7.13 avec scandir et voici ma fonction de recursive à une doublure 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

https://pypi.python.org/pypi/scandir

0
répondu Akarius 2017-03-28 14:12:55

quand la taille des sous-répertoires est calculée, il doit mettre à jour la taille du dossier de son parent et cela va continuer jusqu'à ce qu'il atteigne le parent racine.

La fonction suivante calcule la taille du dossier et 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
0
répondu Nirvik Ghosh 2017-05-07 11:58:04

Pour ce que ça vaut... la commande tree fait tout cela gratuitement:

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

j'aime Python, mais de loin la solution la plus simple au problème ne nécessite pas de nouveau code.

0
répondu meh 2017-07-25 18:01:25

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 pour la taille du dossier en MB. J'ai dû utiliser IF et elif pour le dossier racine parce que sinon subprocess soulève l'erreur due à la valeur non-nulle retourné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
0
répondu Tomas Oliver Ramilison 2018-03-20 02:24:54
import os

def get_size(path):
    total_size = 0
    for dirpath, dirnames, filenames in os.walk(path):
        for f in filenames:
            if os.path.exists(fp):
                fp = os.path.join(dirpath, f)
                total_size += os.path.getsize(fp)

    return total_size   # in megabytes

Merci monkut & troex! Cela fonctionne vraiment bien!

-1
répondu BARSPIN 2014-05-24 23:46:34