Web'de, insan tarafından okunabilir boyutu bayt boyutundan döndürmek için bir işlev verecek çeşitli snippet'ler vardır:
>>> human_readable(2048)
'2 kilobytes'
>>>
Ama bunu sağlayan bir Python kütüphanesi var mı?
Web'de, insan tarafından okunabilir boyutu bayt boyutundan döndürmek için bir işlev verecek çeşitli snippet'ler vardır:
>>> human_readable(2048)
'2 kilobytes'
>>>
Ama bunu sağlayan bir Python kütüphanesi var mı?
Yanıtlar:
Basit bir uygulama ile yukarıdaki "kütüphane gerektirecek çok küçük bir görev" sorununu ele almak:
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)
Destekler:
Misal:
>>> sizeof_fmt(168963795964)
'157.4GiB'
ile Fred Cirera
B
(yani bayt dışındaki birimler için ) herhangi bir (?) sonek için faktörün hayır 1000.0
yerine olmasını ister misiniz 1024.0
?
1
4. ve 6. satırlarda istediğiniz hassasiyeti değiştirin.
Aradığınız tüm işlevselliğe sahip bir kütüphane humanize
. humanize.naturalsize()
aradığınız her şeyi yapıyor gibi görünüyor.
humanize.naturalsize(2048) # => '2.0 kB'
,humanize.naturalsize(2048, binary=True) # => '2.0 KiB'
humanize.naturalsize(2048, gnu=True) # => '2.0K'
İşte benim versiyonum. For-loop kullanmaz. Sürekli karmaşıklığa sahiptir, O ( 1 ) ve teoride burada bir for-loop kullanan cevaplardan daha verimlidir.
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'
Neler olup bittiğini daha açık hale getirmek için dize biçimlendirmesinin kodunu atlayabiliriz. İşte işi yapan çizgiler:
exponent = int(log(num, 1024))
quotient = num / 1024**exponent
unit_list[exponent]
1000
olarak gösterecektir 1,000 bytes
.
unit_list = list(zip(['bytes', 'kB', 'MB', 'GB', 'TB', 'PB'], [0, 0, 1, 2, 2, 2]))
Python 3.6 + 'da aşağıdaki çalışmalar, bence, burada cevabı anlamanın en kolay yolu ve kullanılan ondalık basamak miktarını özelleştirmenizi sağlar.
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}"
Bu sorunun eski olduğunu bilsem de, yakın zamanda döngülerden kaçınan log2
ve sonek listesine bir kaydırma ve bir dizin olarak iki katına çıkan boyut sırasını belirlemek için bir sürüm buldum :
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])
Yine de okunabilirliği için unpythonic olarak düşünülebilir :)
size
veya (1 << (order * 10)
içinde float()
(piton 2 için) son satırında.
import math
orada olması gerekebilir .
Her zaman bu adamlardan biri olmalı. Bugün benim. İşte tek satırlık bir çözüm - veya işlev imzasını sayarsanız iki satır.
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
bunun yerine kullanarak )
Yüklü Django kullanıyorsanız filesizeformat'ı da deneyebilirsiniz :
from django.template.defaultfilters import filesizeformat
filesizeformat(1073741824)
=>
"1.0 GB"
Böyle bir kütüphane acele . Dosya boyutu .
>>> from hurry.filesize import alternative
>>> size(1, system=alternative)
'1 byte'
>>> size(10, system=alternative)
'10 bytes'
>>> size(1024, system=alternative)
'1 KB'
1000 veya kibibit güçlerden birini kullanmak daha standart dostu olacaktır:
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 K (büyük harf) son ekiyle binlerce basan bir kütüphaneye asla güvenmeyin :)
P.S. Never trust a library that prints thousands with the K (uppercase) suffix :)
Neden olmasın? Kod mükemmel olabilir ve yazar sadece kasayı kilo olarak düşünmedi. Kuralınıza göre herhangi bir kodu otomatik olarak reddetmek oldukça asinine benziyor ...
Bu, neredeyse her durumda ihtiyacınız olanı yapacak, isteğe bağlı argümanlar ile özelleştirilebilir ve gördüğünüz gibi, hemen hemen kendi kendini belgelendirir:
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)
Örnek çıktı:
>>> 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'
Gelişmiş özelleştirmeler:
>>> 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'
Bu kod hem Python 2 hem de Python 3 uyumludur. PEP8 uyumluluğu okuyucu için bir alıştırmadır. Unutmayın, güzel olan çıktı .
Güncelleme:
Binlerce virgül gerekiyorsa, belirgin uzantıyı uygulayın:
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))
Örneğin:
>>> pretty_units(987654321098765432109876543210)
'816,968.5 YiB'
"İnsanlaştırmak" gerekir.
>>> humanize.naturalsize(1000000)
'1.0 MB'
>>> humanize.naturalsize(1000000, binary=True)
'976.6 KiB'
>>> humanize.naturalsize(1000000, gnu=True)
'976.6K'
Referans:
Hurry.filesize () yöntemine alternatif olarak sağlanan snippet'e dayanarak, burada kullanılan önek temelinde değişen kesinlik sayıları veren bir snippet bulunmaktadır. Bazı parçacıklar kadar kısa değil, ama sonuçları seviyorum.
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)
HumanFriendly projesi bu konuda yardımcı olur .
import humanfriendly
humanfriendly.format_size(1024)
Yukarıdaki kod cevap olarak 1KB verecektir.
Örnekler burada bulunabilir .
Önceki tüm cevaplardan çizim, işte benim üstlenmem. Dosya boyutunu baytlarda bir tamsayı olarak saklayacak bir nesnedir. Ancak nesneyi yazdırmaya çalıştığınızda, otomatik olarak okunabilir bir sürüm elde edersiniz.
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)
Senderle'ın ondalık sürümünün sabit hassasiyetini seviyorum , bu yüzden yukarıdaki joctee cevabı ile bir çeşit melez (tamsayı olmayan üslerle günlükler alabileceğinizi biliyor muydunuz?):
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 da konuşur bu işlevi hakkında.
Modern Django'nun kendi şablon etiketi var filesizeformat
:
Değeri bir human-readable
dosya boyutu gibi biçimlendirir (yani '13 KB ',' 4,1 MB ',' 102 bayt 'vb.).
Örneğin:
{{ value|filesizeformat }}
Değer 123456789 ise, çıktı 117,7 MB olur.
Daha fazla bilgi: https://docs.djangoproject.com/en/1.10/ref/templates/builtins/#filesizeformat
Basit bir 2 astar hakkında:
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])
Kaputun altında nasıl çalıştığı aşağıda açıklanmıştır:
Kb
, dolayısıyla yanıt X KiB olmalıdır)file_size/value_of_closest_unit
ünitesi ile birlikte.Ancak dosya boyutu 0 veya negatifse çalışmaz (günlük 0 ve -ve sayıları için tanımsız olduğu için). Onlar için ek kontroller ekleyebilirsiniz:
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])
Örnekler:
>>> humanizeFileSize(538244835492574234)
'478.06 PiB'
>>> humanizeFileSize(-924372537)
'881.55 MiB'
>>> humanizeFileSize(0)
'0 Bytes'
NOT - Kb ve KiB arasında bir fark vardır. KB 1000 bayt, KiB ise 1024 bayt anlamına gelir. KB, MB, GB vb KiB, MiB, GiB oysa 1024 tüm katları olan, 1000 katlarıdır burada bu konuda daha fazla
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
Aşağıda bulmak üzere olduğunuz şey, daha önce yayınlanmış olanlar arasında hiçbir şekilde en performanslı veya en kısa çözüm değildir. Bunun yerine, diğer cevapların çoğunun kaçırdığı belirli bir konuya odaklanmaktadır .
Yani giriş gibi bir 999_995
durum verildiğinde:
Python 3.6.1 ...
...
>>> value = 999_995
>>> base = 1000
>>> math.log(value, base)
1.999999276174054
ki, en yakın tamsayıya kısaltılır ve girdiye geri uygulanır.
>>> order = int(math.log(value, base))
>>> value/base**order
999.995
Bu, çıktı hassasiyetini kontrol etmemiz gerekene kadar tam olarak beklediğimiz gibi görünüyor . İşte işler biraz zorlaşmaya başladığında.
2 haneye ayarlanan hassasiyetle:
>>> round(value/base**order, 2)
1000 # K
yerine 1M
.
Buna nasıl karşı koyabiliriz?
Tabii ki, açıkça kontrol edebiliriz:
if round(value/base**order, 2) == base:
order += 1
Ama daha iyisini yapabilir miyiz? order
Son adımı atmadan önce hangi yoldan kesilmesi gerektiğini öğrenebilir miyiz?
Olabiliriz.
0.5 ondalık yuvarlama kuralı varsayarsak, yukarıdaki if
koşul şuna dönüşür:
sonuçlanan
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]}'
vererek
>>> 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'
başvurunun Sridhar Ratnakumar
yanıtı, güncellendi:
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)
ve örnek çıktı:
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
Bu çözüm, zihninizin nasıl çalıştığına bağlı olarak size de hitap edebilir:
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'