Python에서 파일 크기를 변환하는 더 나은 방법
파일을 읽고 크기를 바이트 단위로 반환하는 라이브러리를 사용하고 있습니다.
이 크기가됩니다. 이해할 수 크기를 으로 " 면이파크최사종표게에시다니됩자용기가그러일"로 합니다. 사용자가 쉽게 이해할 수 있도록 파일 크기를 다음으로 명시적으로 변환합니다.MB
로나어누로 .1024.0 * 1024.0
물론 이것은 효과가 있지만, 저는 이것을 파이썬에서 하는 더 나은 방법이 있는지 궁금합니다.
더 나은 것은 아마도 내가 원하는 유형에 따라 크기를 조작할 수 있는 stdlib 함수를 의미합니다.예를 들어 다음과 같이 지정MB
그것은 자동으로 그것을 다음으로 나눕니다.1024.0 * 1024.0
이 선들에 뭔가가 있습니다.
제가 사용하는 것은 다음과 같습니다.
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 : 크기는 바이트 단위로 전송해야 합니다.
크기를 바이트 단위로 가져가서 문자열을 잘 만들 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 * 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
다음은 원하는 장치 크기를 이미 알고 있는 경우 사용하기 쉬운 하나의 라이너입니다.몇 가지 좋은 옵션이 포함된 보다 일반적인 기능을 찾고 있다면 2021년 2월 업데이트에서 다음 정보를 참조하십시오.
바이트
print(f"{os.path.getsize(filepath):,} B")
킬로비트
print(f"{os.path.getsize(filepath)/(1<<7):,.0f} kb")
킬로바이트
print(f"{os.path.getsize(filepath)/(1<<10):,.0f} KB")
메가비트
print(f"{os.path.getsize(filepath)/(1<<17):,.0f} mb")
메가바이트
print(f"{os.path.getsize(filepath)/(1<<20):,.0f} MB")
기가비트
print(f"{os.path.getsize(filepath)/(1<<27):,.0f} gb")
기가바이트
print(f"{os.path.getsize(filepath)/(1<<30):,.0f} GB")
테라바이트
print(f"{os.path.getsize(filepath)/(1<<40):,.0f} TB")
2021년 2월 업데이트 a) 파일/폴더 크기 가져오기 b) 원하는 단위로 변환하기 위해 업데이트되고 확장된 기능은 다음과 같습니다.
from pathlib import Path
def get_path_size(path = Path('.'), recursive=False):
"""
Gets file size, or total directory size
Parameters
----------
path: str | pathlib.Path
File path or directory/folder path
recursive: bool
True -> use .rglob i.e. include nested files and directories
False -> use .glob i.e. only process current directory/folder
Returns
-------
int:
File size or recursive directory size in bytes
Use cleverutils.format_bytes to convert to other units e.g. MB
"""
path = Path(path)
if path.is_file():
size = path.stat().st_size
elif path.is_dir():
path_glob = path.rglob('*.*') if recursive else path.glob('*.*')
size = sum(file.stat().st_size for file in path_glob)
return size
def format_bytes(bytes, unit, SI=False):
"""
Converts bytes to common units such as kb, kib, KB, mb, mib, MB
Parameters
---------
bytes: int
Number of bytes to be converted
unit: str
Desired unit of measure for output
SI: bool
True -> Use SI standard e.g. KB = 1000 bytes
False -> Use JEDEC standard e.g. KB = 1024 bytes
Returns
-------
str:
E.g. "7 MiB" where MiB is the original unit abbreviation supplied
"""
if unit.lower() in "b bit bits".split():
return f"{bytes*8} {unit}"
unitN = unit[0].upper()+unit[1:].replace("s","") # Normalised
reference = {"Kb Kib Kibibit Kilobit": (7, 1),
"KB KiB Kibibyte Kilobyte": (10, 1),
"Mb Mib Mebibit Megabit": (17, 2),
"MB MiB Mebibyte Megabyte": (20, 2),
"Gb Gib Gibibit Gigabit": (27, 3),
"GB GiB Gibibyte Gigabyte": (30, 3),
"Tb Tib Tebibit Terabit": (37, 4),
"TB TiB Tebibyte Terabyte": (40, 4),
"Pb Pib Pebibit Petabit": (47, 5),
"PB PiB Pebibyte Petabyte": (50, 5),
"Eb Eib Exbibit Exabit": (57, 6),
"EB EiB Exbibyte Exabyte": (60, 6),
"Zb Zib Zebibit Zettabit": (67, 7),
"ZB ZiB Zebibyte Zettabyte": (70, 7),
"Yb Yib Yobibit Yottabit": (77, 8),
"YB YiB Yobibyte Yottabyte": (80, 8),
}
key_list = '\n'.join([" b Bit"] + [x for x in reference.keys()]) +"\n"
if unitN not in key_list:
raise IndexError(f"\n\nConversion unit must be one of:\n\n{key_list}")
units, divisors = [(k,v) for k,v in reference.items() if unitN in k][0]
if SI:
divisor = 1000**divisors[1]/8 if "bit" in units else 1000**divisors[1]
else:
divisor = float(1 << divisors[0])
value = bytes / divisor
return f"{value:,.0f} {unitN}{(value != 1 and len(unitN) > 3)*'s'}"
# Tests
>>> assert format_bytes(1,"b") == '8 b'
>>> assert format_bytes(1,"bits") == '8 bits'
>>> assert format_bytes(1024, "kilobyte") == "1 Kilobyte"
>>> assert format_bytes(1024, "kB") == "1 KB"
>>> assert format_bytes(7141000, "mb") == '54 Mb'
>>> assert format_bytes(7141000, "mib") == '54 Mib'
>>> assert format_bytes(7141000, "Mb") == '54 Mb'
>>> assert format_bytes(7141000, "MB") == '7 MB'
>>> assert format_bytes(7141000, "mebibytes") == '7 Mebibytes'
>>> assert format_bytes(7141000, "gb") == '0 Gb'
>>> assert format_bytes(1000000, "kB") == '977 KB'
>>> assert format_bytes(1000000, "kB", SI=True) == '1,000 KB'
>>> assert format_bytes(1000000, "kb") == '7,812 Kb'
>>> assert format_bytes(1000000, "kb", SI=True) == '8,000 Kb'
>>> assert format_bytes(125000, "kb") == '977 Kb'
>>> assert format_bytes(125000, "kb", SI=True) == '1,000 Kb'
>>> assert format_bytes(125*1024, "kb") == '1,000 Kb'
>>> assert format_bytes(125*1024, "kb", SI=True) == '1,024 Kb'
2022년 10월 업데이트
최근 댓글에 대한 답변이 너무 길어서 1<<20 마법에 대한 추가 설명이 있습니다!또한 플로트가 필요하지 않다는 것을 알게 되어 위의 예에서 제거했습니다.
다른 응답(위)에서 언급한 바와 같이 "<"을 "비트 연산자"라고 합니다.왼쪽을 이진으로 변환하고 이진 숫자를 왼쪽으로 20자리 이동합니다(이 경우).우리가 정상적으로 십진법으로 계산할 때, 총 자릿수는 우리가 십진법, 백진법, 천진법, 백만진법 등에 도달했는지 여부를 나타냅니다.자릿수를 제외한 이진법의 유사한 것은 우리가 말하는 비트, 바이트, 킬로바이트, 메가바이트 등을 나타냅니다.따라서... 1<20은 실제로 (이진) 1 뒤에 0이 20개 있는 (이진) 1과 동일합니다. 또는 2진수에서 1048576에 해당하는 20의 거듭제곱(2**20)으로 변환하는 방법을 기억하는 경우입니다.위의 스니펫에서 os.path.getsize는 Bytes로 값을 반환하며 1048576바이트는 엄격하게 Mibyte(MiB)를 말하고 일반적으로 메가바이트(MB)를 말합니다.
크기를 계산하기 위한 컴팩트 함수입니다.
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 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
산출량
>>> convert_bytes(1024)
'1.0 KB'
>>> convert_bytes(102400)
'100.0 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
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)
위아래로 주조가 가능하고 사용자 정의 가능한 정밀도가 추가된 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
기타, 당신이 원하는 대로.
저는 2방향 변환을 원했고, 파이썬 3 포맷() 지원을 가장 파이썬적으로 사용하고 싶었습니다.데이터 크기 라이브러리 모듈을 사용해 보시겠습니까?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.'
여기 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)
최대 3자리 숫자를 인쇄하고 뒤에 오는 0과 마침표를 제거합니다.부울 매개 변수si
크기 크기를 2-10 기반과 비교하여 사용합니다.
이것이 그것의 대응물입니다.다음과 같은 깨끗한 구성 파일을 쓸 수 있습니다.{'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)
언급URL : https://stackoverflow.com/questions/5194057/better-way-to-convert-file-sizes-in-python
'programing' 카테고리의 다른 글
Application_Start of Global.aspx에서 전체 호스트 이름 + 포트 번호를 가져오는 방법은 무엇입니까? (0) | 2023.08.08 |
---|---|
ActiveWindow를 사용하지 않고 VBA를 사용하여 Excel에서 격자선을 끄는 방법 (0) | 2023.08.08 |
node.js가 웹 서버라고 할 수 있습니까? (0) | 2023.07.29 |
파워셸에서 정적 메서드를 호출하는 방법 (0) | 2023.07.29 |
utf8mb3 테이블에 이모지를 저장할 수 없습니다...MariaDB 10.6 업데이트 이후 하룻밤 사이에 nd_mysqli로 전환 (0) | 2023.07.29 |