Calcolo delle dimensioni di una directory usando Python?


182

Prima di reinventare questa particolare ruota, qualcuno ha una buona routine per calcolare la dimensione di una directory usando Python? Sarebbe molto bello se la routine formattasse le dimensioni in Mb / Gb ecc.


13
NON sarebbe molto bello. Dovresti avere una funzione per calcolare la dimensione e una funzione abbastanza indipendente (che potrebbe essere usata anche con dimensioni di memoria, ad esempio) per "formattare la dimensione in Mb / Gb ecc.".
John Machin,

17
Sì, lo so, ma questo fa risparmiare facendo due domande.
Gary Willoughby,

1
Il treecomando sui sistemi * nix fa tutto questo gratuitamente. tree -h -d --du /path/to/dir.
Meh

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

Risposte:


252

Questo include tutte le sottodirectory; somma delle dimensioni dei file:

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 un oneliner per divertimento usando os.listdir ( non include sottodirectory ):

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

Riferimento:

Aggiornato Per usare os.path.getsize , questo è più chiaro dell'uso del metodo os.stat (). St_size.

Grazie a ghostdog74 per averlo segnalato!

os.stat - st_size Fornisce la dimensione in byte. Può anche essere usato per ottenere dimensioni del file e altre informazioni relative al file.

import os

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

Aggiornamento 2018

Se si utilizza Python 3.4 o precedente, è possibile prendere in considerazione l'utilizzo del walkmetodo più efficiente fornito dal scandirpacchetto di terze parti . In Python 3.5 e versioni successive, questo pacchetto è stato incorporato nella libreria standard e os.walkha ricevuto il corrispondente aumento delle prestazioni.

Aggiornamento 2019

Recentemente ho usato pathlibsempre di più, ecco una pathlibsoluzione:

from pathlib import Path

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

14
+1 ma l'Oneliner non restituisce un risultato valido perché non ricorsivo
luc

2
Sì, è solo per il caso della directory flat.
monkut,

35
Per un vero divertimento puoi fare una dimensione ricorsiva in una riga: sum (os.path.getsize (os.path.join (dirpath, nomefile)) per dirpath, dirnames, nomi file in os.walk (PATH) per nomefile nei nomi file)
driax,

2
Ma devi usare st_sizese non vuoi seguire i symlink, come dovresti usare lstat.
asmeurer

3
Avvertimento! questo non è lo stesso di 'du -sb'. Vedi la risposta di Samuel Lampa! Il codice ignora la dimensione della cartella utilizzata per archiviare FAT.
Yauhen Yakimovich,

43

Alcuni degli approcci suggeriti finora implementano una ricorsione, altri impiegano una shell o non produrranno risultati ben formattati. Quando il tuo codice è una tantum per piattaforme Linux, puoi ottenere la formattazione come al solito, ricorsione inclusa, come una riga. Tranne che printnell'ultima riga, funzionerà con le versioni correnti di 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('.'))

è semplice, efficiente e funzionerà per file e directory multilivello:

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

13
Nb. Solo Linux.
meawoppl,

15
Python, essendo di natura multipiattaforma, dovrebbe probabilmente evitarlo
Jonathan,

11
Grazie per queste osservazioni. Ho aggiunto un avvertimento sulla dipendenza dalla piattaforma alla risposta. Tuttavia, gran parte del codice Python se scripting una tantum. Tale codice non dovrebbe comportare limitazioni funzionali, passaggi lunghi e soggetti a errori o risultati non comuni in casi limite, solo per motivi di portabilità oltre ogni necessità . Come sempre, è un compromesso ed è responsabilità dello sviluppatore scegliere saggiamente;)
flaschbier,

9
Nitpick: non Linux ma specifico per Unix / Posix :)
Mr Shark,

3
È probabilmente saggio aggiungere l'opzione '-x' al comando du per limitare la ricerca al filesystem. In altre parole, utilizzare invece ['du', '-shx', path].
Keith Hanlan,

24

Ecco una funzione ricorsiva (riassume ricorsivamente la dimensione di tutte le sottocartelle e dei rispettivi file) che restituisce esattamente gli stessi byte di quando si esegue "du -sb". in linux (dove "." significa "la cartella corrente"):

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
Questa funzione calcola anche la dimensione del collegamento simbolico: se si desidera saltare i collegamenti simbolici, è necessario verificare che non sia questo: if os.path.isfile (itempath) e os.path.islink (itempath) ed elif os.path.isdir ( itempath) e os.path.islink (itempath).
trasmesso il

17

Dimensione della cartella ricorsiva di 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
Metodo Python 3 one-liner se non preoccupato per la ricorsività sum([entry.stat().st_size for entry in os.scandir(file)]). L'output della nota è in byte, / 1024 per ottenere KB e / (1024 * 1024) per ottenere MB.
weiji14,

4
@ weiji14 Perdere le parentesi, ad es sum(entry.stat().st_size for entry in os.scandir(file)). Nessun motivo per fare un elenco, perché sumrichiede anche iteratori.
Vedran Šego,

8

la risposta di monknut è buona ma non funziona con il collegamento simbolico interrotto, quindi devi anche verificare se questo percorso esiste davvero

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

3
Probabilmente non vorrai seguire i symlink. Si dovrebbe usare lstat.
asmeurer

8

La risposta accettata non tiene conto dei collegamenti rigidi o software e conterebbe questi file due volte. Vorresti tenere traccia degli inode che hai visto e non aggiungere le dimensioni per quei file.

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
Prendi in considerazione l'uso os.lstat(anziché os.stat), che evita i seguenti collegamenti simbolici: docs.python.org/2/library/os.html#os.lstat
Peter Briggs

7

La risposta di Chris è buona, ma potrebbe essere resa più idiomatica usando un set per verificare la presenza di directory viste, il che evita anche l'uso di un'eccezione per il flusso di controllo:

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 risposta di Chris, inoltre, non tiene conto dei collegamenti simbolici né delle dimensioni delle directory stesse. Ho modificato la tua risposta di conseguenza, l'output della funzione fissa è ora identico a df -sb.
Creshal,

7

un one-liner ricorsivo:

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
Tuttavia, non è una linea. Tuttavia, calcola in modo ricorsivo la dimensione della cartella (anche se la cartella contiene più cartelle all'interno) in byte e fornisce il valore corretto.
Venkatesh,

Sono andato per questo come facile da usare e ho lavorato per la prima volta su Windows
hum3

5

Per la seconda parte della domanda

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 pathlibsono arrivato questo one-liner per ottenere le dimensioni di una cartella:

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

E questo è quello che ho pensato per un output ben formattato:

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)

Ho anche incontrato questa domanda , che ha alcune strategie più compatte e probabilmente più performanti per la stampa di file di dimensioni.


4

Puoi fare qualcosa del genere:

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

in questo caso non ho testato il risultato prima di restituirlo, se lo si desidera è possibile verificarlo con command.getstatusoutput.


come sono le prestazioni rispetto all'uso os.walkper controllare ricorsivamente le dimensioni della sottocartella?
TomSawyer,


4

Un po 'in ritardo alla festa, ma in una linea a condizione di avere glob2 e umanizzare installato. Si noti che in Python 3, l'impostazione predefinita iglobha una modalità ricorsiva. Come modificare il codice per Python 3 è lasciato come un esercizio banale per il lettore.

>>> 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 partire da Python 3.5, il built-in globsupporta la ricorsione. Puoi usare:glob.glob('/var/**', recursive=True)
adzenith,

3

Il seguente script stampa la dimensione della directory di tutte le sottodirectory per la directory specificata. Cerca anche di beneficiare (se possibile) della memorizzazione nella cache delle chiamate di funzioni ricorsive. Se un argomento viene omesso, lo script funzionerà nella directory corrente. L'output è ordinato in base alla dimensione della directory dalla più grande alla più piccola. Quindi puoi adattarlo alle tue esigenze.

PS: ho usato la ricetta 578019 per mostrare le dimensioni della directory in un formato adatto all'uomo ( 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())

Uscita campione:

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: spostato null_decorator sopra, come raccomandato da user2233949


Lo script funziona bene, ma è necessario spostare la funzione null_decorator sopra la riga 'if sys.version_info> = ...'. Altrimenti otterrai un 'null_decorator' non un'eccezione definita. Funziona benissimo dopo quello però.
user2233949

@utente2233949, grazie! Ho modificato il codice di conseguenza.
MaxU

3

usa la libreria sh : il modulo lo dufa:

pip install sh

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

se vuoi passare asterix, usa globcome descritto qui .

per convertire i valori in readable umani, usa humanize :

pip install humanize

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

2

per ottenere la dimensione di un file, c'è os.path.getsize ()

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

è riportato in byte.


2

Per quello che vale ... il comando tree fa tutto questo gratuitamente:

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

Adoro Python, ma la soluzione di gran lunga più semplice al problema non richiede un nuovo codice.


@ Abdur-RahmaanJanhangeer, questo è vero. Questo è vero.
Meh

2

È utile:

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

Sto usando Python 2.7.13 con scandir ed ecco la mia funzione ricorsiva one-liner per ottenere la dimensione totale di una cartella:

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 viene calcolata la dimensione delle sottodirectory, dovrebbe aggiornare la dimensione della cartella del suo genitore e questo andrà avanti fino a raggiungere il genitore principale.

La seguente funzione calcola la dimensione della cartella e di tutte le sue sottocartelle.

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 sei nel sistema operativo Windows puoi fare:

installa il modulo pywin32 avviando:

pip installa pywin32

e quindi codificare quanto segue:

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

Ecco una riga che lo fa in modo ricorsivo (opzione ricorsiva disponibile da 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

per python3.5 +

from pathlib import Path

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

0

Questo script ti dice quale file è il più grande nel CWD e ti dice anche in quale cartella si trova il file. Questo script funziona per me su win8 e 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

Certo, questo è un po 'hacker e funziona solo su Unix / Linux.

Corrisponde du -sb .perché in effetti si tratta di un wrapper bash Python che esegue il 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

Sono un po 'in ritardo (e nuovo) qui, ma ho scelto di utilizzare il modulo di sottoprocesso e la riga di comando' du 'con Linux per recuperare un valore preciso per la dimensione della cartella in MB. Ho dovuto usare if ed elif per la cartella principale perché altrimenti il ​​sottoprocesso genera errori a causa del valore diverso da zero restituito.

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

Ottieni le dimensioni della directory

Proprietà della soluzione:

  • restituisce entrambi: la dimensione apparente (numero di byte nel file) e lo spazio su disco effettivo utilizzato dai file.
  • conta i file hard link solo una volta
  • conta i collegamenti simbolici allo stesso modo du fa
  • non usa la ricorsione
  • utilizza st.st_blocksper lo spazio su disco utilizzato, quindi funziona solo su sistemi simili a Unix

Il codice:

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)

Esempio di utilizzo:

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

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

Dimensione del file leggibile dall'uomo

Proprietà della soluzione:

Il codice:

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)

Esempio di utilizzo:

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

0

Una soluzione che funziona su Python 3.6 usando pathlib.

from pathlib import Path

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

0

Python 3.6+ dimensione della cartella / file ricorsiva usando os.scandir. Potente come nella risposta di @blakev, ma più breve e in stile pitone 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

Ho scritto questa funzione che mi dà le dimensioni complessive precise di una directory, ne ho provate altre per soluzioni loop con os.walk ma non so perché il risultato finale sia sempre stato inferiore alla dimensione effettiva (su Ubuntu 18 env). Devo aver fatto qualcosa di sbagliato ma chi se ne frega di questo ha funzionato perfettamente.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.