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?
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?
Antworten:
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:
Beispiel:
>>> sizeof_fmt(168963795964)
'157.4GiB'
von Fred Cirera
B
(dh für andere Einheiten als Bytes) möchten Sie, dass der Faktor 1000.0
eher als 1024.0
nein ist?
1
Zeilen 4 und 6 auf die gewünschte Genauigkeit.
Eine Bibliothek mit allen Funktionen, nach denen Sie suchen, ist humanize
. humanize.naturalsize()
scheint alles zu tun, was Sie suchen.
humanize.naturalsize(2048) # => '2.0 kB'
,humanize.naturalsize(2048, binary=True) # => '2.0 KiB'
humanize.naturalsize(2048, gnu=True) # => '2.0K'
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]
1000
würde also als anzeigen 1,000 bytes
.
unit_list = list(zip(['bytes', 'kB', 'MB', 'GB', 'TB', 'PB'], [0, 0, 1, 2, 2, 2]))
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}"
Obwohl ich weiß, dass diese Frage uralt ist, habe ich kürzlich eine Version entwickelt, die Schleifen vermeidet und log2
die 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 :)
size
oder (1 << (order * 10)
in float()
die letzte Zeile einschließen (für Python 2).
import math
oben vielleicht etwas .
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
units=None
stattdessen verwenden)
Wenn Sie Django installiert verwenden, können Sie auch das Dateigrößenformat ausprobieren :
from django.template.defaultfilters import filesizeformat
filesizeformat(1073741824)
=>
"1.0 GB"
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'
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 :)
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 ...
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'
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:
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)
Das HumanFriendly-Projekt hilft dabei .
import humanfriendly
humanfriendly.format_size(1024)
Der obige Code gibt 1 KB als Antwort.
Beispiele finden Sie hier .
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)
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')
DiveIntoPython3 auch spricht auch über diese Funktion.
Moderne Django haben Selbstvorlagen-Tag filesizeformat
:
Formatiert den Wert wie a human-readable
Dateigröße (z. B. '13 KB ',' 4.1 MB ',' 102 Bytes 'usw.).
Beispielsweise:
{{ value|filesizeformat }}
Wenn der Wert 123456789 ist, würde die Ausgabe 117,7 MB betragen.
Weitere Informationen: https://docs.djangoproject.com/de/1.10/ref/templates/builtins/#filesizeformat
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:
Kb
, daher sollte die Antwort X KiB sein)file_size/value_of_closest_unit
zusammen 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
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
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_995
gegeben 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 order
geschnitten 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 if
Bedingung:
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'
Sridhar Ratnakumar
Antwort 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
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'