Python에서 파일 크기를 변환하는 더 나은 방법
파일을 읽고 크기를 바이트 단위로 반환하는 라이브러리를 사용하고 있습니다.
이 파일 크기는 최종 사용자에게 표시됩니다. 쉽게 그들에게 내가 명시 적으로 파일 크기를 변환하고, 그것을 이해 할 수 있도록하기 MB
로 나누어 1024.0 * 1024.0
. 물론 이것은 작동하지만 Python에서 이것을 수행하는 더 좋은 방법이 있는지 궁금합니다.
더 나은 것은 내가 원하는 유형에 따라 크기를 조작 할 수있는 stdlib 함수를 의미합니다. 지정 MB
하면 자동으로로 나눕니다 1024.0 * 1024.0
. 이 라인에 Somethign.
이 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'
Awesome Martijn Faassen이 작성했기 때문에 코드는 작고 명확하며 확장 가능합니다. 자신의 시스템을 작성하는 것은 매우 쉽습니다.
다음은 하나입니다.
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'
내가 사용하는 것은 다음과 같습니다.
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])
주의 : 크기는 바이트 단위로 전송되어야합니다.
크기 제수 대신 비트 이동 연산자를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
다음은 크기를 계산하는 압축 함수입니다.
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/ 를 참조하십시오.
누군가 가이 문제의 반대를 찾고있는 경우를 대비하여 (확실히했듯이) 여기에 효과가 있습니다.
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
원하는 것을 이미 알고있는 경우 한 줄의 코드로 파일 크기를 인쇄하는 빠르고 비교적 읽기 쉬운 방법은 아래를 참조하십시오. 이 한 줄짜리는 위의 @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의 비디오 편집기) MB이고 때로는 비디오 클립의 경우 GB입니다.
PATHLIB를 사용 하여 업데이트 Hildy의 의견에 대한 답으로, 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
>>> 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'
여기에 내 2 센트는 위아래로 캐스팅 할 수 있고 사용자 정의 가능한 정밀도를 추가합니다.
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
원하는대로 등을 추가 합니다.
다음은 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
내 구현은 다음과 같습니다.
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)
소수점 세 자리까지 인쇄하고 후행 0과 마침표를 제거합니다. 부울 매개 변수 si
는 10 기반 및 2 기반 크기 크기 사용을 전환합니다.
This is its counterpart. It allows to write clean configuration files like {'maximum_filesize': from_filesize('10M')
. It returns an integer that approximates the intended filesize. I am not using bit shifting because the source value is a floating point number (it will accept from_filesize('2.15M')
just fine). Converting it to an integer/decimal would work but makes the code more complicated and it already works as it is.
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)
Here's another version of @romeo's reverse implementation that handles a single input string.
import re
def get_bytes(size_string):
try:
size_string = size_string.lower().replace(',', '')
size = re.search('^(\d+)[a-z]i?b$', size_string).groups()[0]
suffix = re.search('^\d+([kmgtp])i?b$', size_string).groups()[0]
except AttributeError:
raise ValueError("Invalid Input")
shft = suffix.translate(str.maketrans('kmgtp', '12345')) + '0'
return int(size) << int(shft)
Similar to Aaron Duke's reply but more "pythonic" ;)
import re
RE_SIZE = re.compile(r'^(\d+)([a-z])i?b?$')
def to_bytes(s):
parts = RE_SIZE.search(s.lower().replace(',', ''))
if not parts:
raise ValueError("Invalid Input")
size = parts.group(1)
suffix = parts.group(2)
shift = suffix.translate(str.maketrans('kmgtp', '12345')) + '0'
return int(size) << int(shift)
I'm new to programming. I came up with this following function that converts a given file size into readable format.
def file_size_converter(size):
magic = lambda x: str(round(size/round(x/1024), 2))
size_in_int = [int(1 << 10), int(1 << 20), int(1 << 30), int(1 << 40), int(1 << 50)]
size_in_text = ['B', 'KB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB']
for i in size_in_int:
if size < i:
g = size_in_int.index(i)
position = int((1024 % i) / 1024 * g)
ss = magic(i)
return ss + ' ' + size_in_text[position]
This work correctly for all file sizes:
import math
from os.path import getsize
def convert_size(size):
if (size == 0):
return '0B'
size_name = ("B", "KB", "MB", "GB", "TB", "PB", "EB", "ZB", "YB")
i = int(math.floor(math.log(size,1024)))
p = math.pow(1024,i)
s = round(size/p,2)
return '%s %s' % (s,size_name[i])
print(convert_size(getsize('file_name.zip')))
참고URL : https://stackoverflow.com/questions/5194057/better-way-to-convert-file-sizes-in-python
'Programing' 카테고리의 다른 글
$ .post와 $ .ajax의 차이점은 무엇입니까? (0) | 2020.12.07 |
---|---|
"if x then return"뒤에 "else"가 거의 사용되지 않는 이유는 무엇입니까? (0) | 2020.12.06 |
작업 공급자를 작업 공급자를 공유하도록 캐스팅 할 수 없습니다. (0) | 2020.12.06 |
배열의 모든 요소를 동일한 숫자로 초기화 (0) | 2020.12.06 |
Honeycomb 작업 표시 줄에서 응용 프로그램 아이콘 및 제목 제거 (0) | 2020.12.06 |