Я использую библиотеку, которая читает файл и возвращает его размер в байтах.
Этот размер файла затем отображается для конечного пользователя; чтобы им было легче понять это, я явно конвертирую размер файла в MB
, деля его на 1024.0 * 1024.0
. Конечно, это работает, но мне интересно, есть ли лучший способ сделать это в Python?
Под лучшим я имею в виду, возможно, функцию stdlib, которая может управлять размерами в соответствии с типом, который я хочу. Например, если я укажу MB
, он автоматически делит его на 1024.0 * 1024.0
. Что-нибудь в этом роде.
kB (Kilo) for 1.000 Byte
иKiB (Kibi) for 1.024 Byte
. См. En.wikipedia.org/wiki/Kibibyte .Ответы:
Существует hurry.filesize , который принимает размер в байтах и в этом случае создает красивую строку.
>>> from hurry.filesize import size >>> size(11000) '10K' >>> size(198283722) '189M'
Или, если вы хотите 1K == 1000 (что предполагает большинство пользователей):
>>> from hurry.filesize import size, si >>> size(11000, system=si) '11K' >>> size(198283722, system=si) '198M'
Он также поддерживает IEC (но это не было задокументировано):
>>> from hurry.filesize import size, iec >>> size(11000, system=iec) '10Ki' >>> size(198283722, system=iec) '189Mi'
Поскольку он написан Прекрасным Мартином Фаассеном, код небольшой, понятный и расширяемый. Написать свою собственную систему очень просто.
Вот один из них:
mysystem = [ (1024 ** 5, ' Megamanys'), (1024 ** 4, ' Lotses'), (1024 ** 3, ' Tons'), (1024 ** 2, ' Heaps'), (1024 ** 1, ' Bunches'), (1024 ** 0, ' Thingies'), ]
Используется так:
>>> from hurry.filesize import size >>> size(11000, system=mysystem) '10 Bunches' >>> size(198283722, system=mysystem) '189 Heaps'
источник
1024
(int).MBFACTOR = float(1 << 20); mb= int(size_in_bytes) / MBFACTOR
@LennartRegebroВот что я использую:
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])
NB: размер должен быть отправлен в байтах.
источник
Вместо делителя размера
1024 * 1024
вы можете использовать<<
оператор побитового сдвига , т.е.1<<20
для получения мегабайт,1<<30
для получения гигабайт и т. Д.В простейшем случае вы можете иметь , например , константу ,
MBFACTOR = float(1<<20)
которая затем может быть использована с байтами, то есть:megas = size_in_bytes/MBFACTOR
.Обычно все, что вам нужно, это мегабайты, или можно использовать что-то вроде этого:
# 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
источник
>>
ли?0
.Вот компактная функция для расчета размера
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])
Для более подробного вывода и наоборот, пожалуйста, обратитесь: http://code.activestate.com/recipes/578019-bytes-to-human-human-to-bytes-converter/
источник
См. Ниже быстрый и относительно простой для чтения способ печати размеров файлов в одной строке кода, если вы уже знаете, что хотите. Эти однострочники сочетают в себе отличный ответ @ccpizza выше с некоторыми удобными приемами форматирования, которые я прочитал здесь Как напечатать число с запятыми в качестве разделителей тысяч? .
Байтов
print ('{:,.0f}'.format(os.path.getsize(filepath))+" B")
Килобиты
print ('{:,.0f}'.format(os.path.getsize(filepath)/float(1<<7))+" kb")
Килобайт
print ('{:,.0f}'.format(os.path.getsize(filepath)/float(1<<10))+" KB")
Мегабит
print ('{:,.0f}'.format(os.path.getsize(filepath)/float(1<<17))+" mb")
Мегабайт
print ('{:,.0f}'.format(os.path.getsize(filepath)/float(1<<20))+" MB")
Гигабит
print ('{:,.0f}'.format(os.path.getsize(filepath)/float(1<<27))+" gb")
Гигабайт
print ('{:,.0f}'.format(os.path.getsize(filepath)/float(1<<30))+" GB")
Терабайт
print ('{:,.0f}'.format(os.path.getsize(filepath)/float(1<<40))+" TB")
Очевидно, они предполагают, что вы примерно знаете, с каким размером вы собираетесь иметь дело с самого начала, который в моем случае (видеоредактор на South West London TV) составляет МБ, а иногда и ГБ для видеоклипов.
ОБНОВЛЕНИЕ С ИСПОЛЬЗОВАНИЕМ PATHLIB В ответ на комментарий Хильди, вот мое предложение для компактной пары функций (сохраняя элементы «атомарными», а не объединяя их), используя только стандартную библиотеку Python:
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'
источник
На всякий случай, если кто-то ищет обратную сторону этой проблемы (как я уверен), вот что работает для меня:
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
источник
<< 10
чтобы* 1024
,<< 20
чтобы* 1024**2
и<< 30
в* 1024**3
.Вот:
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
источник
Вот мои два цента, которые позволяют забрасывать вверх и вниз и добавляют настраиваемую точность:
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)
Добавляйте
TB
и тд, как хотите.источник
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)
источник
Вот версия, которая соответствует выводу 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
источник
Я хотел двухстороннее преобразование, и я хотел использовать поддержку Python 3 format (), чтобы сделать его максимально питоническим. Может быть, попробовать модуль библиотеки 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.'
источник
Вот моя реализация:
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)
Он печатает до трех знаков после запятой и удаляет завершающие нули и точки. Логический параметр
si
будет переключать использование величины размера на основе 10 и 2.Это его аналог. Это позволяет писать чистые файлы конфигурации, такие как
{'maximum_filesize': from_filesize('10M')
. Он возвращает целое число, приблизительно равное предполагаемому размеру файла. Я не использую битовый сдвиг, потому что исходное значение - это число с плавающей запятой (оноfrom_filesize('2.15M')
прекрасно подойдет ). Преобразование его в целое / десятичное сработает, но усложняет код, и он уже работает как есть.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)
источник