152 votes

Meilleure façon de convertir la taille des fichiers en Python

J'utilise une bibliothèque qui lit un fichier et renvoie sa taille en octets.

Cette taille de fichier est ensuite affichée à l'utilisateur final ; pour faciliter sa compréhension, je convertis explicitement la taille du fichier en MB en le divisant par 1024.0 * 1024.0 . Bien sûr, cela fonctionne, mais je me demande s'il y a une meilleure façon de faire cela en Python ?

Par mieux, j'entends peut-être une fonction stdlib qui peut manipuler les tailles en fonction du type que je souhaite. Par exemple, si je spécifie MB il le divise automatiquement par 1024.0 * 1024.0 . Quelque chose de ce genre.

2voto

Jeremy Points 51

Je voulais une conversion dans les deux sens, et je voulais utiliser le support de format() de Python 3 pour être le plus pythonique possible. Peut-être essayer le module de la bibliothèque datasize ? https://pypi.org/project/datasize/

$ pip install -qqq datasize
$ python
...
>>> from datasize import DataSize
>>> 'My new {:GB} SSD really only stores {:.2GiB} of data.'.format(DataSize('750GB'),DataSize(DataSize('750GB') * 0.8))
'My new 750GB SSD really only stores 558.79GiB of data.'

-1voto

sebleblanc Points 586

Voici comment je procède :

from bisect import bisect

def to_filesize(bytes_num, si=True):
    decade = 1000 if si else 1024
    partitions = tuple(decade ** n for n in range(1, 6))
    suffixes = tuple('BKMGTP')

    i = bisect(partitions, bytes_num)
    s = suffixes[i]

    for n in range(i):
        bytes_num /= decade

    f = '{:.3f}'.format(bytes_num)

    return '{}{}'.format(f.rstrip('0').rstrip('.'), s)

Il imprime jusqu'à trois décimales et supprime les zéros et les points qui suivent. Le paramètre booléen si permet d'alterner l'utilisation d'une magnitude de taille basée sur 10 et d'une magnitude de taille basée sur 2.

Voici son pendant. Il permet d'écrire des fichiers de configuration propres comme {'maximum_filesize': from_filesize('10M') . Il renvoie un nombre entier qui correspond approximativement à la taille de fichier prévue. Je n'utilise pas de décalage de bits parce que la valeur source est un nombre à virgule flottante (il acceptera from_filesize('2.15M') très bien). La conversion en nombre entier/décimal fonctionnerait, mais rendrait le code plus compliqué, alors qu'il fonctionne déjà tel quel.

def from_filesize(spec, si=True):
    decade = 1000 if si else 1024
    suffixes = tuple('BKMGTP')

    num = float(spec[:-1])
    s = spec[-1]
    i = suffixes.index(s)

    for n in range(i):
        num *= decade

    return int(num)

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X