Ada berbagai cuplikan di web yang akan memberi Anda fungsi untuk mengembalikan ukuran yang dapat dibaca manusia dari ukuran byte:
>>> human_readable(2048)
'2 kilobytes'
>>>
Tetapi apakah ada perpustakaan Python yang menyediakan ini?
Ada berbagai cuplikan di web yang akan memberi Anda fungsi untuk mengembalikan ukuran yang dapat dibaca manusia dari ukuran byte:
>>> human_readable(2048)
'2 kilobytes'
>>>
Tetapi apakah ada perpustakaan Python yang menyediakan ini?
Jawaban:
Mengatasi masalah "tugas yang terlalu kecil untuk memerlukan pustaka" di atas dengan implementasi langsung:
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)
Mendukung:
Contoh:
>>> sizeof_fmt(168963795964)
'157.4GiB'
oleh Fred Cirera
B
(yaitu untuk unit selain byte) Anda ingin faktor menjadi 1000.0
daripada 1024.0
bukan?
1
garis on 4 dan 6 ke ketepatan yang Anda inginkan.
Perpustakaan yang memiliki semua fungsi yang tampaknya Anda cari adalah humanize
. humanize.naturalsize()
tampaknya melakukan semua yang Anda cari.
humanize.naturalsize(2048) # => '2.0 kB'
,humanize.naturalsize(2048, binary=True) # => '2.0 KiB'
humanize.naturalsize(2048, gnu=True) # => '2.0K'
Ini versiku. Itu tidak menggunakan for-loop. Ini memiliki kompleksitas konstan, O ( 1 ), dan secara teori lebih efisien daripada jawaban di sini yang menggunakan for-loop.
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'
Untuk membuatnya lebih jelas apa yang sedang terjadi, kita dapat menghilangkan kode untuk pemformatan string. Berikut adalah baris yang benar-benar melakukan pekerjaan:
exponent = int(log(num, 1024))
quotient = num / 1024**exponent
unit_list[exponent]
1000
akan ditampilkan sebagai 1,000 bytes
.
unit_list = list(zip(['bytes', 'kB', 'MB', 'GB', 'TB', 'PB'], [0, 0, 1, 2, 2, 2]))
Karya-karya berikut di Python 3.6+, adalah, menurut pendapat saya, jawaban termudah untuk dipahami di sini, dan memungkinkan Anda menyesuaikan jumlah tempat desimal yang digunakan.
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}"
Meskipun saya tahu pertanyaan ini kuno, saya baru-baru ini membuat versi yang menghindari loop, gunakan log2
untuk menentukan urutan ukuran yang berfungsi ganda sebagai pergeseran dan indeks ke dalam daftar akhiran:
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])
Bisa juga dianggap unpythonic karena mudah dibaca, :)
size
atau (1 << (order * 10)
di float()
dalam baris terakhir (untuk python 2).
import math
di sana.
Pasti selalu ada salah satu dari mereka. Baiklah hari ini saya. Inilah solusi satu-liner - atau dua baris jika Anda menghitung tanda tangan fungsi.
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
sebagai gantinya menggunakan )
Jika Anda menggunakan Django terinstal, Anda juga dapat mencoba format filesize :
from django.template.defaultfilters import filesizeformat
filesizeformat(1073741824)
=>
"1.0 GB"
Salah satu perpustakaan semacam itu adalah rush.filesize .
>>> from hurry.filesize import alternative
>>> size(1, system=alternative)
'1 byte'
>>> size(10, system=alternative)
'10 bytes'
>>> size(1024, system=alternative)
'1 KB'
Menggunakan kekuatan 1000 atau kibibytes akan lebih ramah-standar:
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 Jangan pernah percaya perpustakaan yang mencetak ribuan dengan akhiran K (huruf besar) :)
P.S. Never trust a library that prints thousands with the K (uppercase) suffix :)
Kenapa tidak? Kode dapat terdengar sempurna dan penulis tidak mempertimbangkan casing untuk kilo. Tampaknya cukup bodoh untuk secara otomatis mengabaikan kode apa pun berdasarkan aturan Anda ...
Ini akan melakukan apa yang Anda butuhkan di hampir semua situasi, dapat disesuaikan dengan argumen opsional, dan seperti yang Anda lihat, cukup banyak mendokumentasikan diri:
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)
Contoh output:
>>> 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'
Kustomisasi lanjutan:
>>> 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'
Kode ini kompatibel dengan Python 2 dan Python 3. Kepatuhan PEP8 adalah latihan untuk pembaca. Ingat, outputnya cantik.
Memperbarui:
Jika Anda membutuhkan ribuan koma, cukup terapkan ekstensi yang jelas:
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))
Sebagai contoh:
>>> pretty_units(987654321098765432109876543210)
'816,968.5 YiB'
Anda harus menggunakan "memanusiakan".
>>> humanize.naturalsize(1000000)
'1.0 MB'
>>> humanize.naturalsize(1000000, binary=True)
'976.6 KiB'
>>> humanize.naturalsize(1000000, gnu=True)
'976.6K'
Referensi:
Riffing pada snippet yang disediakan sebagai alternatif untuk terburu-buru.filesize (), di sini adalah snippet yang memberikan angka presisi yang bervariasi berdasarkan awalan yang digunakan. Tidak sesempit beberapa cuplikan, tapi saya suka hasilnya.
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)
Proyek HumanFriendly membantu dalam hal ini .
import humanfriendly
humanfriendly.format_size(1024)
Kode di atas akan memberikan 1KB sebagai jawaban.
Contohnya dapat ditemukan di sini .
Menarik dari semua jawaban sebelumnya, inilah pendapat saya. Ini adalah objek yang akan menyimpan ukuran file dalam byte sebagai integer. Tetapi ketika Anda mencoba untuk mencetak objek, Anda secara otomatis mendapatkan versi yang dapat dibaca manusia.
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)
Saya suka ketepatan tetap dari versi desimal pengirim , jadi inilah semacam hibrida dari itu dengan jawaban joctee di atas (apakah Anda tahu Anda dapat mengambil log dengan basis non-integer?):
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 juga berbicara tentang fungsi ini.
Django modern memiliki tag templat mandiri filesizeformat
:
Memformat nilai seperti a human-readable
ukuran file (yaitu '13 KB ',' 4,1 MB ',' 102 byte ', dll.).
Sebagai contoh:
{{ value|filesizeformat }}
Jika nilainya 123456789, output akan menjadi 117,7 MB.
Info lebih lanjut: https://docs.djangoproject.com/en/1.10/ref/templates/builtins/#filesizeformat
Bagaimana dengan 2 liner sederhana:
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])
Inilah cara kerjanya di bawah tenda:
Kb
, jadi jawabannya harus X KiB)file_size/value_of_closest_unit
bersama dengan unit.Namun itu tidak berfungsi jika ukuran file adalah 0 atau negatif (karena log tidak terdefinisi untuk angka 0 dan -ve). Anda dapat menambahkan cek tambahan untuk mereka:
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])
Contoh:
>>> humanizeFileSize(538244835492574234)
'478.06 PiB'
>>> humanizeFileSize(-924372537)
'881.55 MiB'
>>> humanizeFileSize(0)
'0 Bytes'
CATATAN - Ada perbedaan antara Kb dan KiB. KB berarti 1000 byte, sedangkan KiB berarti 1024 byte. KB, MB, GB semuanya kelipatan 1000, sedangkan KiB, MiB, GiB dll semua kelipatan 1024. Lebih lanjut tentang hal ini di sini
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
Apa yang akan Anda temukan di bawah ini bukanlah solusi yang paling berkinerja atau terpendek di antara yang sudah diposting. Alih-alih, ini berfokus pada satu masalah tertentu yang tidak dijawab oleh banyak jawaban lainnya.
Yaitu kasus ketika input suka 999_995
diberikan:
Python 3.6.1 ...
...
>>> value = 999_995
>>> base = 1000
>>> math.log(value, base)
1.999999276174054
yang, terpotong ke bilangan bulat terdekat dan diterapkan kembali ke input yang diberikan
>>> order = int(math.log(value, base))
>>> value/base**order
999.995
Ini tampaknya persis seperti yang kita harapkan sampai kita diharuskan mengendalikan presisi keluaran . Dan saat inilah segalanya mulai menjadi sedikit sulit.
Dengan presisi yang diatur ke 2 digit, kita dapat:
>>> round(value/base**order, 2)
1000 # K
bukannya 1M
.
Bagaimana kita bisa mengatasinya?
Tentu saja, kita dapat memeriksanya secara eksplisit:
if round(value/base**order, 2) == base:
order += 1
Tetapi bisakah kita melakukan yang lebih baik? Bisakah kita mengetahui jalan mana yang order
harus dipotong sebelum kita melakukan langkah terakhir?
Ternyata kita bisa.
Dengan asumsi 0,5 aturan pembulatan desimal, if
kondisi di atas diterjemahkan menjadi:
yang menghasilkan
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]}'
memberi
>>> 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'
rujuk Sridhar Ratnakumar
jawaban, diperbarui ke:
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)
dan contoh outputnya adalah:
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
Solusi ini mungkin juga menarik bagi Anda, tergantung pada bagaimana pikiran Anda bekerja:
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'