Używam biblioteki, która czyta plik i zwraca jego rozmiar w bajtach.
Ten rozmiar pliku jest następnie wyświetlany użytkownikowi końcowemu; Aby ułatwić im zrozumienie tego, wyraźnie konwertuję rozmiar pliku na MB
, dzieląc go przez 1024.0 * 1024.0
. Oczywiście to działa, ale zastanawiam się, czy istnieje lepszy sposób na zrobienie tego w Pythonie?
Mówiąc lepiej, mam na myśli funkcję standardowej biblioteki, która może manipulować rozmiarami w zależności od typu, który chcę. Tak jak jeśli podam MB
, automatycznie dzieli to przez 1024.0 * 1024.0
. Coś się dzieje na tych liniach.
kB (Kilo) for 1.000 Byte
iKiB (Kibi) for 1.024 Byte
. Zobacz en.wikipedia.org/wiki/Kibibyte .Odpowiedzi:
Jest hurry.filesize , który przyjmie rozmiar w bajtach i utworzy ładny ciąg znaków, jeśli tak.
>>> from hurry.filesize import size >>> size(11000) '10K' >>> size(198283722) '189M'
Lub jeśli chcesz 1K == 1000 (co zakłada większość użytkowników):
>>> from hurry.filesize import size, si >>> size(11000, system=si) '11K' >>> size(198283722, system=si) '198M'
Obsługuje również IEC (ale nie zostało to udokumentowane):
>>> from hurry.filesize import size, iec >>> size(11000, system=iec) '10Ki' >>> size(198283722, system=iec) '189Mi'
Ponieważ został napisany przez Awesome Martijna Faassena, kod jest mały, przejrzysty i rozszerzalny. Pisanie własnych systemów jest niezwykle łatwe.
Tutaj jest jeden:
mysystem = [ (1024 ** 5, ' Megamanys'), (1024 ** 4, ' Lotses'), (1024 ** 3, ' Tons'), (1024 ** 2, ' Heaps'), (1024 ** 1, ' Bunches'), (1024 ** 0, ' Thingies'), ]
Używane tak:
>>> from hurry.filesize import size >>> size(11000, system=mysystem) '10 Bunches' >>> size(198283722, system=mysystem) '189 Heaps'
źródło
1024
(int).MBFACTOR = float(1 << 20); mb= int(size_in_bytes) / MBFACTOR
@LennartRegebroOto czego używam:
import math def convert_size(size_bytes): if size_bytes == 0: return "0B" size_name = ("B", "KB", "MB", "GB", "TB", "PB", "EB", "ZB", "YB") i = int(math.floor(math.log(size_bytes, 1024))) p = math.pow(1024, i) s = round(size_bytes / p, 2) return "%s %s" % (s, size_name[i])
Uwaga: rozmiar należy przesłać w bajtach.
źródło
Zamiast dzielnika rozmiaru
1024 * 1024
możesz użyć<<
operatora przesunięcia bitowego , tj.1<<20
Aby uzyskać megabajty,1<<30
uzyskać gigabajty itp.W najprostszym scenariuszu można mieć np stałym
MBFACTOR = float(1<<20)
, które mogą być następnie wykorzystane w bajtach, a mianowicie:megas = size_in_bytes/MBFACTOR
.Megabajty to zwykle wszystko, czego potrzebujesz, lub w inny sposób można użyć czegoś takiego:
# bytes pretty-printing UNITS_MAPPING = [ (1<<50, ' PB'), (1<<40, ' TB'), (1<<30, ' GB'), (1<<20, ' MB'), (1<<10, ' KB'), (1, (' byte', ' bytes')), ] def pretty_size(bytes, units=UNITS_MAPPING): """Get human-readable file sizes. simplified version of https://pypi.python.org/pypi/hurry.filesize/ """ for factor, suffix in units: if bytes >= factor: break amount = int(bytes / factor) if isinstance(suffix, tuple): singular, multiple = suffix if amount == 1: suffix = singular else: suffix = multiple return str(amount) + suffix print(pretty_size(1)) print(pretty_size(42)) print(pretty_size(4096)) print(pretty_size(238048577)) print(pretty_size(334073741824)) print(pretty_size(96995116277763)) print(pretty_size(3125899904842624)) ## [Out] ########################### 1 byte 42 bytes 4 KB 227 MB 311 GB 88 TB 2 PB
źródło
>>
?0
.Oto kompaktowa funkcja do obliczania rozmiaru
def GetHumanReadable(size,precision=2): suffixes=['B','KB','MB','GB','TB'] suffixIndex = 0 while size > 1024 and suffixIndex < 4: suffixIndex += 1 #increment the index of the suffix size = size/1024.0 #apply the division return "%.*f%s"%(precision,size,suffixes[suffixIndex])
Aby uzyskać bardziej szczegółowe dane wyjściowe i odwrotnie, odwiedź: http://code.activestate.com/recipes/578019-bytes-to-human-human-to-bytes-converter/
źródło
Poniżej znajdziesz szybki i stosunkowo łatwy do odczytania sposób drukowania rozmiarów plików w jednej linii kodu, jeśli już wiesz, czego chcesz. Te jednowierszowe łączą świetną odpowiedź @ccpizza powyżej z przydatnymi sztuczkami formatowania, które przeczytałem tutaj. Jak wydrukować liczbę przecinkami jako separatorami tysięcy? .
Bajty
print ('{:,.0f}'.format(os.path.getsize(filepath))+" B")
Kilobity
print ('{:,.0f}'.format(os.path.getsize(filepath)/float(1<<7))+" kb")
Kilobajty
print ('{:,.0f}'.format(os.path.getsize(filepath)/float(1<<10))+" KB")
Megabity
print ('{:,.0f}'.format(os.path.getsize(filepath)/float(1<<17))+" mb")
Megabajtów
print ('{:,.0f}'.format(os.path.getsize(filepath)/float(1<<20))+" MB")
Gigabity
print ('{:,.0f}'.format(os.path.getsize(filepath)/float(1<<27))+" gb")
Gigabajty
print ('{:,.0f}'.format(os.path.getsize(filepath)/float(1<<30))+" GB")
Terabajty
print ('{:,.0f}'.format(os.path.getsize(filepath)/float(1<<40))+" TB")
Oczywiście zakładają, że wiesz z grubsza, z jakim rozmiarem będziesz mieć do czynienia na początku, który w moim przypadku (edytor wideo w telewizji South West London) wynosi MB, a czasami GB dla klipów wideo.
AKTUALIZACJA ZA POMOCĄ PATHLIB W odpowiedzi na komentarz Hildy'ego , oto moja sugestia dotycząca zwartej pary funkcji (utrzymywanie elementów „atomowych” zamiast ich scalania) przy użyciu tylko standardowej biblioteki Pythona:
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 >>> format_size("d:\\media\\bags of fun.avi") '38 MB' >>> format_size("d:\\media\\bags of fun.avi","KB") '38,763 KB' >>> format_size("d:\\media\\bags of fun.avi","kb") '310,104 kb'
źródło
Na wszelki wypadek, gdyby ktoś szukał odwrotności tego problemu (tak jak na pewno), oto, co działa dla mnie:
def get_bytes(size, suffix): size = int(float(size)) suffix = suffix.lower() if suffix == 'kb' or suffix == 'kib': return size << 10 elif suffix == 'mb' or suffix == 'mib': return size << 20 elif suffix == 'gb' or suffix == 'gib': return size << 30 return False
źródło
<< 10
się* 1024
,<< 20
by* 1024**2
i<< 30
do* 1024**3
.Oto ona:
def convert_bytes(size): for x in ['bytes', 'KB', 'MB', 'GB', 'TB']: if size < 1024.0: return "%3.1f %s" % (size, x) size /= 1024.0 return size
źródło
Oto moje dwa centy, które pozwalają na rzucanie w górę iw dół oraz dodaje dostosowywalnej precyzji:
def convertFloatToDecimal(f=0.0, precision=2): ''' Convert a float to string of decimal. precision: by default 2. If no arg provided, return "0.00". ''' return ("%." + str(precision) + "f") % f def formatFileSize(size, sizeIn, sizeOut, precision=0): ''' Convert file size to a string representing its value in B, KB, MB and GB. The convention is based on sizeIn as original unit and sizeOut as final unit. ''' assert sizeIn.upper() in {"B", "KB", "MB", "GB"}, "sizeIn type error" assert sizeOut.upper() in {"B", "KB", "MB", "GB"}, "sizeOut type error" if sizeIn == "B": if sizeOut == "KB": return convertFloatToDecimal((size/1024.0), precision) elif sizeOut == "MB": return convertFloatToDecimal((size/1024.0**2), precision) elif sizeOut == "GB": return convertFloatToDecimal((size/1024.0**3), precision) elif sizeIn == "KB": if sizeOut == "B": return convertFloatToDecimal((size*1024.0), precision) elif sizeOut == "MB": return convertFloatToDecimal((size/1024.0), precision) elif sizeOut == "GB": return convertFloatToDecimal((size/1024.0**2), precision) elif sizeIn == "MB": if sizeOut == "B": return convertFloatToDecimal((size*1024.0**2), precision) elif sizeOut == "KB": return convertFloatToDecimal((size*1024.0), precision) elif sizeOut == "GB": return convertFloatToDecimal((size/1024.0), precision) elif sizeIn == "GB": if sizeOut == "B": return convertFloatToDecimal((size*1024.0**3), precision) elif sizeOut == "KB": return convertFloatToDecimal((size*1024.0**2), precision) elif sizeOut == "MB": return convertFloatToDecimal((size*1024.0), precision)
Dodaj
TB
itp., Jak chcesz.źródło
UNITS = {1000: ['KB', 'MB', 'GB'], 1024: ['KiB', 'MiB', 'GiB']} def approximate_size(size, flag_1024_or_1000=True): mult = 1024 if flag_1024_or_1000 else 1000 for unit in UNITS[mult]: size = size / mult if size < mult: return '{0:.3f} {1}'.format(size, unit) approximate_size(2123, False)
źródło
Oto wersja, która pasuje do wyniku ls -lh .
def human_size(num: int) -> str: base = 1 for unit in ['B', 'K', 'M', 'G', 'T', 'P', 'E', 'Z', 'Y']: n = num / base if n < 9.95 and unit != 'B': # Less than 10 then keep 1 decimal place value = "{:.1f}{}".format(n, unit) return value if round(n) < 1000: # Less than 4 digits so use this value = "{}{}".format(round(n), unit) return value base *= 1024 value = "{}{}".format(round(n), unit) return value
źródło
Chciałem dwukierunkowej konwersji i chciałem, aby obsługa formatu () w Pythonie 3 była jak najbardziej Pythonowa. Może wypróbować moduł biblioteki 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.'
źródło
Oto moja realizacja:
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)
Drukuje do trzech miejsc po przecinku i usuwa końcowe zera i kropki. Parametr boolowski
si
będzie przełączać użycie wielkości opartej na 10 i na 2.To jest jego odpowiednik. Pozwala na pisanie czystych plików konfiguracyjnych, takich jak
{'maximum_filesize': from_filesize('10M')
. Zwraca liczbę całkowitą, która przybliża zamierzony rozmiar pliku. Nie używam przesuwania bitów, ponieważ wartość źródłowa jest liczbą zmiennoprzecinkową (zaakceptujefrom_filesize('2.15M')
to dobrze). Konwersja na liczbę całkowitą / dziesiętną działałaby, ale czyni kod bardziej skomplikowanym i już działa tak, jak jest.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)
źródło