Een door mensen leesbare versie van de bestandsgrootte verkrijgen?

Een functie om de door mensen leesbare grootte terug te geven van de grootte van de bytes:

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

Hoe doe je dit?


Antwoord 1, autoriteit 100%

Het bovenstaande “te kleine taak om een ​​bibliotheek nodig te hebben” oplossen door een eenvoudige implementatie (met behulp van f-strings, dus Python 3.6+):

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

Ondersteunt:

  • alle momenteel bekende binaire voorvoegsels
  • negatieve en positieve getallen
  • getallen groter dan 1000 Yobibytes
  • willekeurige eenheden (misschien vind je het leuk om in Gibibits te tellen!)

Voorbeeld:

>>> sizeof_fmt(168963795964)
'157.4GiB'

door Fred Cirera


Antwoord 2, autoriteit 24%

Een bibliotheek met alle functionaliteit die u zoekt, is humanize. humanize.naturalsize()lijkt alles te doen wat je zoekt.


Antwoord 3, autoriteit 7%

Het volgende werkt in Python 3.6+, is naar mijn mening het gemakkelijkst te begrijpen antwoord hier, en laat je het aantal gebruikte decimalen aanpassen.

def human_readable_size(size, decimal_places=2):
    for unit in ['B', 'KiB', 'MiB', 'GiB', 'TiB', 'PiB']:
        if size < 1024.0 or unit == 'PiB':
            break
        size /= 1024.0
    return f"{size:.{decimal_places}f} {unit}"

Antwoord 4, autoriteit 6%

Hier is mijn versie. Het maakt geen gebruik van een for-loop. Het heeft een constante complexiteit, O(1), en is in theorie efficiënter dan de antwoorden hier die een for-loop gebruiken.

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'

Om het duidelijker te maken wat er aan de hand is, kunnen we de code voor de tekenreeksopmaak weglaten. Dit zijn de regels die het werk daadwerkelijk doen:

exponent = int(log(num, 1024))
quotient = num / 1024**exponent
unit_list[exponent]

Antwoord 5, autoriteit 6%

Er moet altijd een van die jongens zijn. Nou, vandaag ben ik het. Hier is een one-liner — of twee regels als je de functiehandtekening meetelt.

def human_size(bytes, units=[' bytes','KB','MB','GB','TB', 'PB', 'EB']):
    """ Returns a human readable string representation 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

Als je maten groter dan een Exabyte nodig hebt, is het een beetje lastiger:

def human_size(bytes, units=[' bytes','KB','MB','GB','TB', 'PB', 'EB']):
    return str(bytes) + units[0] if bytes < 1024 else human_size(bytes>>10, units[1:]) if units[1:] else f'{bytes>>10}ZB'

Antwoord 6, Autoriteit 4%

Ik heb onlangs een versie bedacht die lussen vermijdt, met log2om de maatregel te bepalen die verdubbelt als een verschuiving en een index in de achtervoeglijst:

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])

kan echter welbeschadigd worden beschouwd voor de leesbaarheid ervan.


Antwoord 7, Autoriteit 4%

Als u Django gebruikt, kunt u ook filesizeFormat :

from django.template.defaultfilters import filesizeformat
filesizeformat(1073741824)
=>
"1.0 GB"

Antwoord 8, Autoriteit 2%

U moet “Humanize” gebruiken.

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

Referentie:

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


Antwoord 9, Autoriteit 2%

Eén van een dergelijke bibliotheek is haast.FileSize .

>>> from hurry.filesize import alternative
>>> size(1, system=alternative)
'1 byte'
>>> size(10, system=alternative)
'10 bytes'
>>> size(1024, system=alternative)
'1 KB'

Antwoord 10

Gebruik van beide bevoegdheden van 1000 of kibibytes zou meer standaardvriendelijk zijn:

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)

P.S. Vertrouw nooit een bibliotheek die duizenden afdrukt met het achtervoegsel K (hoofdletters)


Antwoord 11

Het menselijke project helpt met deze .

import humanfriendly
humanfriendly.format_size(1024)

De bovenstaande code geeft 1KB als antwoord.
Voorbeelden is hier te vinden .


Antwoord 12

Dit zal doen wat u nodig heeft in bijna elke situatie, is aanpasbaar met optionele argumenten, en zoals u kunt zien, bevindt zich MOOI Veel zelfdocumentatie:

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)

Voorbeelduitgang:

>>> 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'

Geavanceerde aanpassingen:

>>> 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'

Deze code is zowel compatibel met Python 2 als Python 3. PEP8-compliance is een oefening voor de lezer. Onthoud dat het de outputis die mooi is.

Bijwerken:

Als u duizenden komma’s nodig heeft, past u gewoon de voor de hand liggende extensie toe:

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))

Bijvoorbeeld:

>>> pretty_units(987654321098765432109876543210)
'816,968.5 YiB'

Antwoord 13

Riffing op het fragment dat wordt geleverd als alternatief voor haast.filesize(), hier is een fragment dat verschillende precisiegetallen geeft op basis van het gebruikte voorvoegsel. Het is niet zo beknopt als sommige fragmenten, maar ik vind de resultaten leuk.

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)

Antwoord 14

Gebaseerd op alle eerdere antwoorden, hier is mijn mening erover. Het is een object dat de bestandsgrootte in bytes opslaat als een geheel getal. Maar wanneer u het object probeert af te drukken, krijgt u automatisch een voor mensen leesbare versie.

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)

Antwoord 15

Moderne Django heeft een eigen sjabloontag filesizeformat:

Maakt de waarde op als een human-readablebestandsgrootte (d.w.z. ’13 KB’, ‘4.1 MB’, ‘102 bytes’, enz.).

Bijvoorbeeld:

{{ value|filesizeformat }}

Als de waarde 123456789 is, zou de uitvoer 117,7 MB zijn.

Meer info: https://docs.djangoproject.com /en/1.10/ref/templates/builtins/#filesizeformat


Antwoord 16

Ik hou van de vaste precisie van senderle de decimale versie , dus hier is een soort hybride van die met het antwoord van joctee’s hierboven ( wist je dat je zou kunnen houtblokken met niet-integer basen):?

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')

Antwoord 17

Wat dacht je van een eenvoudige 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])

Hier is hoe het werkt onder de motorkap:

  1. berekent log 2 (bestandsgrootte)
  2. deelt het door 10 naar de dichtstbijzijnde eenheid te krijgen. (Bijvoorbeeld als grootte is 5000 bytes, de dichtstbijzijnde unit is Kb, zodat het antwoord X KiB zou moeten zijn)
  3. Returns file_size/value_of_closest_unitsamen met eenheid.

Het echter werkt niet als bestandsgrootte is 0 of negatief is (omdat log is niet gedefinieerd voor 0 en ve nummers). U kunt extra controles toe te voegen voor hen:

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])

voorbeelden:

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

Opmerking – Er is een verschil tussen Kb en KiB. KB betekent 1000 bytes, terwijl KiB betekent 1024 bytes. KB, MB, GB zijn veelvouden van 1000, terwijl KiB, MiB, GiB etc zijn veelvouden van 1024. Meer over het hier


Antwoord 18

Wat je op het punt om hieronder is geenszins de meest performante of de kortste oplossing onder hen die al gepost. In plaats daarvan richt zich op het een bepaalde kwestie dat veel van de andere antwoorden missen.

name het geval als de ingang zoals 999_995gegeven:

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

die afgeknot het dichtstbijzijnde gehele getal en toegevoerd naar de ingang geeft

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

Dit lijkt precies wat we zouden verwachten totdat we die nodig zijn om de controle uitgang precisie . En dit is wanneer dingen beginnen een beetje moeilijk te krijgen.

Met de precisie ingesteld op 2 cijfers krijgen we:

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

in plaats van 1M.

Hoe kunnen we dat tegen te gaan?

Natuurlijk, we kunnen expliciet controleren dat:

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

Maar kunnen we het beter doen? Kunnen we te weten komen op welke manier de ordermoet worden gesneden voordat we de laatste stap doen?

Het blijkt dat we dat kunnen.

Ervan uitgaande dat de afrondingsregel van 0,5 decimaal decimaal is, vertaalt de bovenstaande if-voorwaarde zich in:

resulterend in

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]}'

geven

>>> 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'

Antwoord 19

Om de bestandsgrootte in een voor mensen leesbare vorm te krijgen, heb ik deze functie gemaakt:

import os
def get_size(path):
    size = os.path.getsize(path)
    if size < 1024:
        return f"{size} bytes"
    elif size < 1024*1024:
        return f"{round(size/1024, 2)} KB"
    elif size < 1024*1024*1024:
        return f"{round(size/(1024*1024), 2)} MB"
    elif size < 1024*1024*1024*1024:
        return f"{round(size/(1024*1024*1024), 2)} GB"
>>> get_size("a.txt")
1.4KB

Antwoord 20

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

Antwoord 21

Deze functie indien beschikbaar in Boltonsdie is een erg handige bibliotheek voor de meeste projecten.

>>> bytes2human(128991)
'126K'
>>> bytes2human(100001221)
'95M'
>>> bytes2human(0, 2)
'0.00B'

Antwoord 22

Hier is een optie met while:

def number_format(n):
   n2, n3 = n, 0
   while n2 >= 1e3:
      n2 /= 1e3
      n3 += 1
   return '%.3f' % n2 + ('', ' k', ' M', ' G')[n3]
s = number_format(9012345678)
print(s == '9.012 G')

https://docs.python.org/reference/compound_stmts.html#while


Antwoord 23

Verwijzend naar het antwoord van Sridhar Ratnakumar, bijgewerkt naar:

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)

en voorbeelduitvoer is:

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

Antwoord 24

Deze oplossing kan u ook aanspreken, afhankelijk van hoe uw geest werkt:

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'

Other episodes