Wiederverwendbare Bibliothek, um eine lesbare Version der Dateigröße zu erhalten?

238

Es gibt verschiedene Snippets im Web, mit denen Sie die lesbare Größe von der Bytegröße zurückgeben können:

>>> human_readable(2048)
'2 kilobytes'
>>>

Aber gibt es eine Python-Bibliothek, die dies bietet?

Sridhar Ratnakumar
quelle
2
Ich denke, dies fällt unter die Überschrift "Eine zu kleine Aufgabe, um eine Bibliothek zu benötigen". Wenn Sie sich die Quelle für hurry.filesize ansehen, gibt es nur eine einzige Funktion mit einem Dutzend Codezeilen. Und selbst das könnte verdichtet werden.
Ben Blank
8
Der Vorteil der Verwendung einer Bibliothek besteht darin, dass sie normalerweise getestet wird (enthält Tests, die ausgeführt werden können, falls die Bearbeitung einen Fehler verursacht). Wenn Sie die Tests hinzufügen, dann ist es nicht mehr 'Dutzend Codezeilen' :-)
Sridhar Ratnakumar
Es ist verrückt und lächerlich, das Rad in der Python-Community neu zu erfinden. Nur ls -h /path/to/file.ext erledigt den Job. Trotzdem macht die akzeptierte Antwort einen guten Job. Kudo.
Edward Aung

Antworten:

522

Behebung des oben genannten Problems "Eine zu kleine Aufgabe, um eine Bibliothek zu benötigen" durch eine einfache Implementierung:

def sizeof_fmt(num, suffix='B'):
    for unit in ['','Ki','Mi','Gi','Ti','Pi','Ei','Zi']:
        if abs(num) < 1024.0:
            return "%3.1f%s%s" % (num, unit, suffix)
        num /= 1024.0
    return "%.1f%s%s" % (num, 'Yi', suffix)

Unterstützt:

  • alle derzeit bekannten binären Präfixe
  • negative und positive Zahlen
  • Zahlen größer als 1000 Yobibyte
  • beliebige Einheiten (vielleicht möchten Sie in Gibibits zählen!)

Beispiel:

>>> sizeof_fmt(168963795964)
'157.4GiB'

von Fred Cirera

Sridhar Ratnakumar
quelle
4
Zwischen der Nummer und dem Gerät sollte ein Leerzeichen sein. Wenn Sie HTML oder Latex ausgeben, sollte dies ein Leerzeichen sein.
Josch
3
Nur ein Gedanke, aber für jedes andere (?) Suffix als B(dh für andere Einheiten als Bytes) möchten Sie, dass der Faktor 1000.0eher als 1024.0nein ist?
Anentropic
5
Wenn Sie die Genauigkeit der Dezimalkomponente erhöhen möchten, ändern Sie die 1Zeilen 4 und 6 auf die gewünschte Genauigkeit.
Matthew G
44
Sicher wäre es schön, wenn all diese Iterationen dieser "zu kleinen Aufgabe" erfasst und mit Tests in eine Bibliothek eingekapselt würden.
Fess.
6
@ MD004 Es ist umgekehrt. Die Präfixe sind so definiert, dass 1 KB = 1000 B und 1 KiB = 1024 B.
August
116

Eine Bibliothek mit allen Funktionen, nach denen Sie suchen, ist humanize. humanize.naturalsize()scheint alles zu tun, was Sie suchen.

Pyrocater
quelle
9
Einige Beispiele mit den Daten aus dem OP : humanize.naturalsize(2048) # => '2.0 kB' ,humanize.naturalsize(2048, binary=True) # => '2.0 KiB' humanize.naturalsize(2048, gnu=True) # => '2.0K'
RubenLaguna
32

Hier ist meine Version. Es wird keine for-Schleife verwendet. Es hat eine konstante Komplexität, O ( 1 ), und ist theoretisch effizienter als die Antworten hier, die eine for-Schleife verwenden.

from math import log
unit_list = zip(['bytes', 'kB', 'MB', 'GB', 'TB', 'PB'], [0, 0, 1, 2, 2, 2])
def sizeof_fmt(num):
    """Human friendly file size"""
    if num > 1:
        exponent = min(int(log(num, 1024)), len(unit_list) - 1)
        quotient = float(num) / 1024**exponent
        unit, num_decimals = unit_list[exponent]
        format_string = '{:.%sf} {}' % (num_decimals)
        return format_string.format(quotient, unit)
    if num == 0:
        return '0 bytes'
    if num == 1:
        return '1 byte'

Um klarer zu machen, was los ist, können wir den Code für die Zeichenfolgenformatierung weglassen. Hier sind die Zeilen, die die Arbeit tatsächlich erledigen:

exponent = int(log(num, 1024))
quotient = num / 1024**exponent
unit_list[exponent]
Joctee
quelle
2
Warum nicht if / elif / else verwenden, während Sie über die Optimierung eines solchen Funktionscodes sprechen? Die letzte Prüfung num == 1 ist nicht erforderlich, es sei denn, Sie erwarten negative Dateigrößen. Ansonsten: gute Arbeit, ich mag diese Version.
Ted
2
Mein Code könnte sicherlich optimierter sein. Mein Ziel war es jedoch zu demonstrieren, dass diese Aufgabe mit konstanter Komplexität gelöst werden kann.
Joctee
37
Die Antworten mit for-Schleifen sind ebenfalls O (1), da die for-Schleifen begrenzt sind - ihre Berechnungszeit skaliert nicht mit der Größe der Eingabe (wir haben keine unbegrenzten SI-Präfixe).
Thomas Minor
1
sollte wahrscheinlich ein Komma für die Formatierung hinzufügen, 1000würde also als anzeigen 1,000 bytes.
iTayb
3
Beachten Sie, dass zip bei Verwendung von Python 3 einen Iterator zurückgibt, sodass Sie ihn mit list () umschließen müssen. unit_list = list(zip(['bytes', 'kB', 'MB', 'GB', 'TB', 'PB'], [0, 0, 1, 2, 2, 2]))
Donarb
30

Die folgenden Arbeiten in Python 3.6+ sind meiner Meinung nach die am einfachsten zu verstehende Antwort hier und ermöglichen es Ihnen, die Anzahl der verwendeten Dezimalstellen anzupassen.

def human_readable_size(size, decimal_places=3):
    for unit in ['B','KiB','MiB','GiB','TiB']:
        if size < 1024.0:
            break
        size /= 1024.0
    return f"{size:.{decimal_places}f}{unit}"
wp-overwatch.com
quelle
26

Obwohl ich weiß, dass diese Frage uralt ist, habe ich kürzlich eine Version entwickelt, die Schleifen vermeidet und log2die Größenreihenfolge bestimmt, die gleichzeitig als Verschiebung und Index in die Suffixliste dient:

from math import log2

_suffixes = ['bytes', 'KiB', 'MiB', 'GiB', 'TiB', 'PiB', 'EiB', 'ZiB', 'YiB']

def file_size(size):
    # determine binary order in steps of size 10 
    # (coerce to int, // still returns a float)
    order = int(log2(size) / 10) if size else 0
    # format file size
    # (.4g results in rounded numbers for exact matches and max 3 decimals, 
    # should never resort to exponent values)
    return '{:.4g} {}'.format(size / (1 << (order * 10)), _suffixes[order])

Könnte aber wegen seiner Lesbarkeit als unpythonisch angesehen werden :)

akaIDIOT
quelle
1
Während ich das log2-Ding mag, solltest du mit size == 0 umgehen!
Marti Nito
Sie müssen entweder sizeoder (1 << (order * 10)in float()die letzte Zeile einschließen (für Python 2).
Harvey
Zu Ihrer Information: Einige brauchen dort import mathoben vielleicht etwas .
Montag,
@monsto true, hinzugefügt :)
akaIDIOT
Liebe, wie kompakt das ist! Ich danke Ihnen für das Teilen.
John Crawford
17

Es muss immer einen dieser Typen geben. Nun, heute bin ich es. Hier ist eine einzeilige Lösung - oder zwei Zeilen, wenn Sie die Funktionssignatur zählen.

def human_size(bytes, units=[' bytes','KB','MB','GB','TB', 'PB', 'EB']):
    """ Returns a human readable string reprentation of bytes"""
    return str(bytes) + units[0] if bytes < 1024 else human_size(bytes>>10, units[1:])

>>> human_size(123)
123 bytes
>>> human_size(123456789)
117GB
wp-overwatch.com
quelle
1
Zu Ihrer Information, die Ausgabe wird immer abgerundet.
wp-overwatch.com
1
Wäre es nicht besser, die Standardliste für Einheiten innerhalb der Methode zuzuweisen, um zu vermeiden, dass eine Liste als Standardargument verwendet wird? (und units=Nonestattdessen verwenden)
Imanol
3
@ImanolEizaguirre Best Practices besagen, dass es eine gute Idee ist, das zu tun, was Sie vorgeschlagen haben, damit Sie nicht versehentlich Fehler in ein Programm einführen. Diese geschriebene Funktion ist jedoch sicher, da die Einheitenliste niemals manipuliert wird. Wenn es manipuliert würde, wären die Änderungen dauerhaft und alle nachfolgenden Funktionsaufrufe würden eine manipulierte Version der Liste als Standardargument für das Einheitenargument erhalten.
wp-overwatch.com
Wenn Sie für Python 3 einen Dezimalpunkt möchten, verwenden Sie stattdessen diesen: `` `def human_size (fsize, unit = ['Bytes', 'KB', 'MB', 'GB', 'TB', 'PB', 'EB']): "{: .2f} {}" zurückgeben. Format (float (fsize), Einheiten [0]) wenn fsize <1024 sonst human_size (fsize / 1024, Einheiten [1:]) `` `
Omer
15

Wenn Sie Django installiert verwenden, können Sie auch das Dateigrößenformat ausprobieren :

from django.template.defaultfilters import filesizeformat
filesizeformat(1073741824)

=>

"1.0 GB"
Jon Tirsen
quelle
1
Ein Nachteil für mich ist, dass es GB anstelle von GiB verwendet, obwohl es durch 1024 geteilt wird.
Pepedou
9

Eine solche Bibliothek ist hurry.filesize .

>>> from hurry.filesize import alternative
>>> size(1, system=alternative)
'1 byte'
>>> size(10, system=alternative)
'10 bytes'
>>> size(1024, system=alternative)
'1 KB'
Sridhar Ratnakumar
quelle
3
Diese Bibliothek ist jedoch nicht sehr anpassbar. >>> von hurry.filesize Importgröße >>> Größe (1031053) >>> Größe (3033053) '2M' Ich erwarte, dass es zum Beispiel '2.4M' oder '2423K' zeigt .. anstelle der offensichtlich angenäherten ' 2M '.
Sridhar Ratnakumar
Beachten Sie auch, dass es sehr einfach ist, den Code aus hurry.filesize herauszuholen und direkt in Ihren eigenen Code einzufügen, wenn Sie mit Abhängigkeitssystemen und dergleichen zu tun haben. Es ist ungefähr so ​​kurz wie die Schnipsel, die die Leute hier zur Verfügung stellen.
mlissner
@SridharRatnakumar, um das Problem der Übernäherung etwas intelligent anzugehen, lesen Sie bitte meinen mathematischen Hack . Kann der Ansatz weiter verbessert werden?
Acumenus
9

Die Verwendung von Potenzen von 1000 oder Kibibyte wäre standardfreundlicher:

def sizeof_fmt(num, use_kibibyte=True):
    base, suffix = [(1000.,'B'),(1024.,'iB')][use_kibibyte]
    for x in ['B'] + map(lambda x: x+suffix, list('kMGTP')):
        if -base < num < base:
            return "%3.1f %s" % (num, x)
        num /= base
    return "%3.1f %s" % (num, x)

PS Vertraue niemals einer Bibliothek, die Tausende mit dem Suffix K (Großbuchstaben) druckt :)

Giancarlo Sportelli
quelle
P.S. Never trust a library that prints thousands with the K (uppercase) suffix :)Warum nicht? Der Code könnte perfekt klingen und der Autor hat das Gehäuse für Kilo einfach nicht in Betracht gezogen. Es scheint ziemlich dumm zu sein, jeden Code basierend auf Ihrer Regel automatisch zu verwerfen ...
Douglas Gaskell
7

Dies wird in fast jeder Situation das tun, was Sie brauchen, ist mit optionalen Argumenten anpassbar und, wie Sie sehen können, ziemlich selbstdokumentierend:

from math import log
def pretty_size(n,pow=0,b=1024,u='B',pre=['']+[p+'i'for p in'KMGTPEZY']):
    pow,n=min(int(log(max(n*b**pow,1),b)),len(pre)-1),n*b**pow
    return "%%.%if %%s%%s"%abs(pow%(-pow-1))%(n/b**float(pow),pre[pow],u)

Beispielausgabe:

>>> pretty_size(42)
'42 B'

>>> pretty_size(2015)
'2.0 KiB'

>>> pretty_size(987654321)
'941.9 MiB'

>>> pretty_size(9876543210)
'9.2 GiB'

>>> pretty_size(0.5,pow=1)
'512 B'

>>> pretty_size(0)
'0 B'

Erweiterte Anpassungen:

>>> pretty_size(987654321,b=1000,u='bytes',pre=['','kilo','mega','giga'])
'987.7 megabytes'

>>> pretty_size(9876543210,b=1000,u='bytes',pre=['','kilo','mega','giga'])
'9.9 gigabytes'

Dieser Code ist sowohl mit Python 2 als auch mit Python 3 kompatibel. Die Einhaltung von PEP8 ist eine Übung für den Leser. Denken Sie daran, es ist die Ausgabe , die hübsch ist.

Aktualisieren:

Wenn Sie Tausende Kommas benötigen, wenden Sie einfach die offensichtliche Erweiterung an:

def prettier_size(n,pow=0,b=1024,u='B',pre=['']+[p+'i'for p in'KMGTPEZY']):
    r,f=min(int(log(max(n*b**pow,1),b)),len(pre)-1),'{:,.%if} %s%s'
    return (f%(abs(r%(-r-1)),pre[r],u)).format(n*b**pow/b**float(r))

Beispielsweise:

>>> pretty_units(987654321098765432109876543210)
'816,968.5 YiB'
gojomo
quelle
7

Sie sollten "humanisieren" verwenden.

>>> humanize.naturalsize(1000000)
'1.0 MB'
>>> humanize.naturalsize(1000000, binary=True)
'976.6 KiB'
>>> humanize.naturalsize(1000000, gnu=True)
'976.6K'

Referenz:

https://pypi.org/project/humanize/

Saeed Zahedian Abroodi
quelle
6

Beim Riffing des als Alternative zu hurry.filesize () bereitgestellten Snippets handelt es sich um ein Snippet, das je nach verwendetem Präfix unterschiedliche Genauigkeitszahlen liefert. Es ist nicht so knapp wie einige Schnipsel, aber ich mag die Ergebnisse.

def human_size(size_bytes):
    """
    format a size in bytes into a 'human' file size, e.g. bytes, KB, MB, GB, TB, PB
    Note that bytes/KB will be reported in whole numbers but MB and above will have greater precision
    e.g. 1 byte, 43 bytes, 443 KB, 4.3 MB, 4.43 GB, etc
    """
    if size_bytes == 1:
        # because I really hate unnecessary plurals
        return "1 byte"

    suffixes_table = [('bytes',0),('KB',0),('MB',1),('GB',2),('TB',2), ('PB',2)]

    num = float(size_bytes)
    for suffix, precision in suffixes_table:
        if num < 1024.0:
            break
        num /= 1024.0

    if precision == 0:
        formatted_size = "%d" % num
    else:
        formatted_size = str(round(num, ndigits=precision))

    return "%s %s" % (formatted_size, suffix)
Markltbaker
quelle
6

Das HumanFriendly-Projekt hilft dabei .

import humanfriendly
humanfriendly.format_size(1024)

Der obige Code gibt 1 KB als Antwort.
Beispiele finden Sie hier .

Arumuga Abinesh
quelle
4

Ausgehend von allen vorherigen Antworten, hier ist meine Sicht darauf. Es ist ein Objekt, das die Dateigröße in Bytes als Ganzzahl speichert. Wenn Sie jedoch versuchen, das Objekt zu drucken, erhalten Sie automatisch eine lesbare Version.

class Filesize(object):
    """
    Container for a size in bytes with a human readable representation
    Use it like this::

        >>> size = Filesize(123123123)
        >>> print size
        '117.4 MB'
    """

    chunk = 1024
    units = ['bytes', 'KB', 'MB', 'GB', 'TB', 'PB']
    precisions = [0, 0, 1, 2, 2, 2]

    def __init__(self, size):
        self.size = size

    def __int__(self):
        return self.size

    def __str__(self):
        if self.size == 0: return '0 bytes'
        from math import log
        unit = self.units[min(int(log(self.size, self.chunk)), len(self.units) - 1)]
        return self.format(unit)

    def format(self, unit):
        if unit not in self.units: raise Exception("Not a valid file size unit: %s" % unit)
        if self.size == 1 and unit == 'bytes': return '1 byte'
        exponent = self.units.index(unit)
        quotient = float(self.size) / self.chunk**exponent
        precision = self.precisions[exponent]
        format_string = '{:.%sf} {}' % (precision)
        return format_string.format(quotient, unit)
xApple
quelle
3

Ich mag die feste Genauigkeit der Absender-Dezimalversion , daher hier eine Art Hybrid davon mit der obigen Antwort von joctee (wussten Sie, dass Sie Protokolle mit nicht ganzzahligen Basen erstellen können?):

from math import log
def human_readable_bytes(x):
    # hybrid of https://stackoverflow.com/a/10171475/2595465
    #      with https://stackoverflow.com/a/5414105/2595465
    if x == 0: return '0'
    magnitude = int(log(abs(x),10.24))
    if magnitude > 16:
        format_str = '%iP'
        denominator_mag = 15
    else:
        float_fmt = '%2.1f' if magnitude % 3 == 1 else '%1.2f'
        illion = (magnitude + 1) // 3
        format_str = float_fmt + ['', 'K', 'M', 'G', 'T', 'P'][illion]
    return (format_str % (x * 1.0 / (1024 ** illion))).lstrip('0')
HST
quelle
2

DiveIntoPython3 auch spricht auch über diese Funktion.

Sridhar Ratnakumar
quelle
2

Wie wäre es mit einem einfachen 2-Liner:

def humanizeFileSize(filesize):
    p = int(math.floor(math.log(filesize, 2)/10))
    return "%.3f%s" % (filesize/math.pow(1024,p), ['B','KiB','MiB','GiB','TiB','PiB','EiB','ZiB','YiB'][p])

So funktioniert es unter der Haube:

  1. Berechnet Protokoll 2 (Dateigröße)
  2. Teilen Sie es durch 10, um die nächste Einheit zu erhalten. (zB wenn die Größe 5000 Bytes beträgt, ist die nächste Einheit Kb, daher sollte die Antwort X KiB sein)
  3. Rückgabe file_size/value_of_closest_unitzusammen mit dem Gerät.

Es funktioniert jedoch nicht, wenn die Dateigröße 0 oder negativ ist (da das Protokoll für 0- und -ve-Zahlen undefiniert ist). Sie können zusätzliche Schecks für sie hinzufügen:

def humanizeFileSize(filesize):
    filesize = abs(filesize)
    if (filesize==0):
        return "0 Bytes"
    p = int(math.floor(math.log(filesize, 2)/10))
    return "%0.2f %s" % (filesize/math.pow(1024,p), ['Bytes','KiB','MiB','GiB','TiB','PiB','EiB','ZiB','YiB'][p])

Beispiele:

>>> humanizeFileSize(538244835492574234)
'478.06 PiB'
>>> humanizeFileSize(-924372537)
'881.55 MiB'
>>> humanizeFileSize(0)
'0 Bytes'

HINWEIS - Es gibt einen Unterschied zwischen Kb und KiB. KB bedeutet 1000 Bytes, während KiB 1024 Bytes bedeutet. KB, MB, GB sind alle Vielfache von 1000, während KiB, MiB, GiB usw. alle Vielfache von 1024 sind. Mehr dazu hier

Jerrymouse
quelle
1
def human_readable_data_quantity(quantity, multiple=1024):
    if quantity == 0:
        quantity = +0
    SUFFIXES = ["B"] + [i + {1000: "B", 1024: "iB"}[multiple] for i in "KMGTPEZY"]
    for suffix in SUFFIXES:
        if quantity < multiple or suffix == SUFFIXES[-1]:
            if suffix == SUFFIXES[0]:
                return "%d%s" % (quantity, suffix)
            else:
                return "%.1f%s" % (quantity, suffix)
        else:
            quantity /= multiple
Matt Joiner
quelle
1

Was Sie unten finden werden, ist keineswegs die leistungsstärkste oder kürzeste Lösung unter den bereits veröffentlichten. Stattdessen konzentriert es sich auf ein bestimmtes Thema , das viele der anderen Antworten übersehen.

Nämlich der Fall, wenn Eingabe wie 999_995gegeben wird:

Python 3.6.1 ...
...
>>> value = 999_995
>>> base = 1000
>>> math.log(value, base)
1.999999276174054

was auf die nächste ganze Zahl gekürzt und wieder auf die Eingabe angewendet wird, ergibt

>>> order = int(math.log(value, base))
>>> value/base**order
999.995

Dies scheint genau das zu sein, was wir erwarten würden, bis wir die Ausgabegenauigkeit steuern müssen . Und dann wird es etwas schwieriger.

Mit der auf 2 Stellen eingestellten Genauigkeit erhalten wir:

>>> round(value/base**order, 2)
1000 # K

statt 1M.

Wie können wir dem entgegenwirken?

Natürlich können wir dies explizit überprüfen:

if round(value/base**order, 2) == base:
    order += 1

Aber können wir es besser machen? Können wir wissen, in welche Richtung das ordergeschnitten werden soll, bevor wir den letzten Schritt machen?

Es stellt sich heraus, dass wir es können.

Unter der Annahme einer Rundungsregel von 0,5 Dezimalstellen bedeutet die obige ifBedingung:

Geben Sie hier die Bildbeschreibung ein

ergebend

def abbreviate(value, base=1000, precision=2, suffixes=None):
    if suffixes is None:
        suffixes = ['', 'K', 'M', 'B', 'T']

    if value == 0:
        return f'{0}{suffixes[0]}'

    order_max = len(suffixes) - 1
    order = log(abs(value), base)
    order_corr = order - int(order) >= log(base - 0.5/10**precision, base)
    order = min(int(order) + order_corr, order_max)

    factored = round(value/base**order, precision)

    return f'{factored:,g}{suffixes[order]}'

geben

>>> abbreviate(999_994)
'999.99K'
>>> abbreviate(999_995)
'1M'
>>> abbreviate(999_995, precision=3)
'999.995K'
>>> abbreviate(2042, base=1024)
'1.99K'
>>> abbreviate(2043, base=1024)
'2K'
Ayorgo
quelle
0

Sridhar RatnakumarAntwort von refer , aktualisiert auf:

def formatSize(sizeInBytes, decimalNum=1, isUnitWithI=False, sizeUnitSeperator=""):
  """format size to human readable string"""
  # https://en.wikipedia.org/wiki/Binary_prefix#Specific_units_of_IEC_60027-2_A.2_and_ISO.2FIEC_80000
  # K=kilo, M=mega, G=giga, T=tera, P=peta, E=exa, Z=zetta, Y=yotta
  sizeUnitList = ['','K','M','G','T','P','E','Z']
  largestUnit = 'Y'

  if isUnitWithI:
    sizeUnitListWithI = []
    for curIdx, eachUnit in enumerate(sizeUnitList):
      unitWithI = eachUnit
      if curIdx >= 1:
        unitWithI += 'i'
      sizeUnitListWithI.append(unitWithI)

    # sizeUnitListWithI = ['','Ki','Mi','Gi','Ti','Pi','Ei','Zi']
    sizeUnitList = sizeUnitListWithI

    largestUnit += 'i'

  suffix = "B"
  decimalFormat = "." + str(decimalNum) + "f" # ".1f"
  finalFormat = "%" + decimalFormat + sizeUnitSeperator + "%s%s" # "%.1f%s%s"
  sizeNum = sizeInBytes
  for sizeUnit in sizeUnitList:
      if abs(sizeNum) < 1024.0:
        return finalFormat % (sizeNum, sizeUnit, suffix)
      sizeNum /= 1024.0
  return finalFormat % (sizeNum, largestUnit, suffix)

und Beispielausgabe ist:

def testKb():
  kbSize = 3746
  kbStr = formatSize(kbSize)
  print("%s -> %s" % (kbSize, kbStr))

def testI():
  iSize = 87533
  iStr = formatSize(iSize, isUnitWithI=True)
  print("%s -> %s" % (iSize, iStr))

def testSeparator():
  seperatorSize = 98654
  seperatorStr = formatSize(seperatorSize, sizeUnitSeperator=" ")
  print("%s -> %s" % (seperatorSize, seperatorStr))

def testBytes():
  bytesSize = 352
  bytesStr = formatSize(bytesSize)
  print("%s -> %s" % (bytesSize, bytesStr))

def testMb():
  mbSize = 76383285
  mbStr = formatSize(mbSize, decimalNum=2)
  print("%s -> %s" % (mbSize, mbStr))

def testTb():
  tbSize = 763832854988542
  tbStr = formatSize(tbSize, decimalNum=2)
  print("%s -> %s" % (tbSize, tbStr))

def testPb():
  pbSize = 763832854988542665
  pbStr = formatSize(pbSize, decimalNum=4)
  print("%s -> %s" % (pbSize, pbStr))


def demoFormatSize():
  testKb()
  testI()
  testSeparator()
  testBytes()
  testMb()
  testTb()
  testPb()

  # 3746 -> 3.7KB
  # 87533 -> 85.5KiB
  # 98654 -> 96.3 KB
  # 352 -> 352.0B
  # 76383285 -> 72.84MB
  # 763832854988542 -> 694.70TB
  # 763832854988542665 -> 678.4199PB
Crifan
quelle
0

Diese Lösung könnte Sie auch ansprechen, je nachdem, wie Ihr Verstand funktioniert:

from pathlib import Path    

def get_size(path = Path('.')):
    """ Gets file size, or total directory size """
    if path.is_file():
        size = path.stat().st_size
    elif path.is_dir():
        size = sum(file.stat().st_size for file in path.glob('*.*'))
    return size

def format_size(path, unit="MB"):
    """ Converts integers to common size units used in computing """
    bit_shift = {"B": 0,
            "kb": 7,
            "KB": 10,
            "mb": 17,
            "MB": 20,
            "gb": 27,
            "GB": 30,
            "TB": 40,}
    return "{:,.0f}".format(get_size(path) / float(1 << bit_shift[unit])) + " " + unit

# Tests and test results
>>> get_size("d:\\media\\bags of fun.avi")
'38 MB'
>>> get_size("d:\\media\\bags of fun.avi","KB")
'38,763 KB'
>>> get_size("d:\\media\\bags of fun.avi","kb")
'310,104 kb'
Peter F.
quelle