Python에서 파일 크기를 변환하는 더 나은 방법


84

파일을 읽고 크기를 바이트 단위로 반환하는 라이브러리를 사용하고 있습니다.

그러면이 파일 크기가 최종 사용자에게 표시됩니다. 쉽게 그들에게 내가 명시 적으로 파일 크기를 변환하고, 그것을 이해 할 수 있도록하기 MB로 나누어 1024.0 * 1024.0. 물론 이것은 작동하지만 Python에서 이것을 수행하는 더 좋은 방법이 있는지 궁금합니다.

더 좋은 것은 내가 원하는 유형에 따라 크기를 조작 할 수있는 stdlib 함수를 의미합니다. 지정 MB하면 자동으로로 나눕니다 1024.0 * 1024.0. 이 라인에 Somethign.


4
그러니 하나 작성하십시오. 또한 많은 시스템은 이제 2 ^ 20 대신 10 ^ 6을 의미하는 MB를 사용합니다.
tc.

5
@AA, @tc : SI 및 IEC 표준은 kB (Kilo) for 1.000 ByteKiB (Kibi) for 1.024 Byte. en.wikipedia.org/wiki/Kibibyte를 참조하십시오 .
Bobby 2011 년

2
@Bobby : kB는 실제로 10000dB와 같은 "킬로 벨"을 의미합니다. 바이트에 대한 SI 단위는 없습니다. IIRC, IEC는 KiB를 권장하지만 kB 또는 KB를 정의하지 않습니다.
tc.

2
@tc. 접두사 kilo는 SI에 의해 정의되어 1000을 의미합니다. IEC는 2 ^ 10 대신 SI 접두사를 사용하기 위해 kB 등을 정의했습니다.
ford

1
접두사는 일반적으로 SI에 의해 정의되지만 데이터 크기의 약어는 physics.nist.gov/cuu/Units/prefixes.html 이 아닙니다 . 이들은 IEC에 의해 정의됩니다 : physics.nist.gov/cuu/Units/binary.html
ford

답변:


100

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'

1
흠, 이제 다른쪽으로 가려면 하나가 필요합니다. "1kb"에서 1024(int)까지.
mlissner

2
파이썬 2에서만 작동합니다
e-info128

2
이 패키지는 멋질 수 있지만 이상한 라이센스와 온라인에서 사용할 수있는 소스 코드가 없다는 사실로 인해 피하고 싶은 것이 있습니다. 또한 python2 만 지원하는 것 같습니다.
Almog Cohen

1
@AlmogCohen 소스는 온라인이고 PyPI에서 바로 사용할 수 있으며 (일부 패키지에는 Github 저장소가없고 PyPI 페이지 만 있음) 라이선스가 그다지 모호하지 않습니다. ZPL은 제가 아는 한 Zope Public License입니다. , BSD 유사. 라이선스 자체가 이상하다는 데 동의합니다. 표준 'LICENSE.txt'파일이 없으며 각 소스 파일의 맨 위에 서문도 없습니다.
sleblanc

1
메가 바이트를 얻기 위해 비트 이동 연산자를 사용하여 다음 방정식을 사용했습니다. MBFACTOR = float(1 << 20); mb= int(size_in_bytes) / MBFACTOR @LennartRegebro
alper

147

내가 사용하는 것은 다음과 같습니다.

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])

주의 : 크기는 바이트 단위로 전송되어야합니다.


11
크기를 바이트 단위로 보내는 경우 size_name의 첫 번째 요소로 "B"를 추가하면됩니다.
tuxGurl 2013 년

크기가 0 바이트 인 파일은 실패합니다. log (0, 1024)가 정의되지 않았습니다! 이 문 i = int (math.floor (math.log (size, 1024))) 전에 0 바이트 케이스를 확인해야합니다.
genclik27

genclik-당신 말이 맞아요. 이 문제를 해결하고 바이트에서 변환 할 수있는 사소한 편집을 방금 제출했습니다. 감사합니다, Sapam 원래위한
FarmerGedden

hi @WHK as tuxGurl은 쉬운 수정을 언급했습니다.
제임스

3
실제로 크기 이름은 ( "B", "KiB", "MiB", "GiB", "TiB", "PiB", "EiB", "ZiB", "YiB") 여야합니다. 자세한 내용은 en.wikipedia.org/wiki/Mebibyte 를 참조하십시오.
Alex

36

크기 제수 대신 비트 이동 연산자를1024 * 1024 사용할 수 있습니다. 즉 , 메가 바이트 를 가져오고 기가 바이트를 가져 오는 등의 작업을 수행 할 수 있습니다.<< 1<<201<<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

10
그렇지 >>않습니까?
Tjorriemorrie 2014-08-08

2
@Tjorriemorrie : 왼쪽 시프트 여야합니다. 오른쪽 시프트는 유일한 비트를 떨어 뜨리고 결과적으로 0.
ccpizza

훌륭한 대답입니다. 감사합니다.
Borislav Aymaliev

나는 이것이 오래되었다는 것을 알고 있지만 이것이 올바른 사용법입니까? DEF convert_to_mb (data_b) 인쇄 (data_b / (1 << 20))
roastbeeef

22

크기를 계산하는 압축 함수는 다음과 같습니다.

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/ 를 참조하십시오.


12

원하는 것을 이미 알고있는 경우 한 줄의 코드로 파일 크기를 인쇄하는 빠르고 비교적 읽기 쉬운 방법은 아래를 참조하십시오. 이 한 줄짜리는 위의 @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
>>> 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'

1
그렇게하는 매우 영리한 방법입니다. kb를 원하는지 여부를 전달하는 함수에 넣을 수 있는지 궁금합니다. MB와 곧. 원하는 것을 묻는 입력 명령을 가질 수도 있습니다.이 작업을 많이 수행하면 매우 편리합니다.
Hildy

위 참조, Hildy ... 위에서 설명한 @ lennart-regebro와 같은 사전 행을 사용자 정의 할 수도 있습니다. 저장소 관리에 유용 할 수 있습니다 (예 : "파티션", "클러스터", "4TB 디스크", "DVD_RW", "). Blu-Ray 디스크 ","1GB ​​메모리 스틱 "또는 기타.
Peter F

또한 Kb (Kilobit), Mb (Megabit) 및 Gb (Gigabit)를 추가했습니다. 사용자는 종종 네트워크 또는 파일 전송 속도 측면에서 혼란스러워서 편리 할 것이라고 생각했습니다.
Peter F

9

누군가 가이 문제의 반대를 찾고있는 경우를 대비하여 (확실히했듯이) 여기에 저에게 효과가 있습니다.

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

1.5GB와 같은 소수의 대소 문자를 처리하지 않습니다. 그것은 단지를 변경 해결하려면 << 10* 1024, << 20* 1024**2<< 30* 1024**3.
E235

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

2

여기에 내 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원하는대로 등을 추가 합니다.


그냥 파이썬 표준 라이브러리 함께 일을 할 수 있기 때문에 나는이 투표를합니다
Ciasto을 piekarz

1

다음은 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

1
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)

이것은 많은 설정에서 사용할 수 있습니다. 이 댓글을 보게되어 기쁩니다. 감사합니다.
Saurabh Jain

0

내 구현은 다음과 같습니다.

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 기반 크기 크기 사용을 전환합니다.

이것은 그에 상응하는 부분입니다. .NET과 같은 깨끗한 구성 파일을 작성할 수 있습니다 {'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)

-1

다음은 단일 입력 문자열을 처리하는 @romeo의 역 구현의 또 다른 버전입니다.

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)

-1

Aaron Duke의 답변과 비슷하지만 더 "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)

-1

저는 프로그래밍이 처음입니다. 주어진 파일 크기를 읽을 수있는 형식으로 변환하는 다음 함수를 생각해 냈습니다.

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]

-2

이것은 모든 파일 크기에 대해 올바르게 작동합니다.

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')))

3
"sapam"의 답변을 복사 할 가치가 있었나요? ... 아니요 .. 다음에 댓글 만 남았습니다.
Angry 84

또 다른 답변은 다른 곳에서 복사 한 다음 여기에 다시 복사해야합니다. 사실 원본을 권장합니다.
WesternGun
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.