biblioteca reutilizável para obter versão legível do tamanho do arquivo?

votos
166

Existem vários trechos na web que lhe daria uma função para retornar o tamanho legível de tamanho bytes:

>>> human_readable(2048)
'2 kilobytes'
>>>

Mas há uma biblioteca Python que fornece esse?

Publicado 07/07/2009 em 21:59
fonte usuário
Em outras línguas...                            


20 respostas

votos
377

Dirigindo-se ao acima "muito pequeno uma tarefa exigir uma biblioteca" questão por uma implementação simples:

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)

Apoios:

  • todos os atualmente conhecidos prefixos binários
  • números negativos e positivos
  • números maiores do que 1000 Yobibytes
  • unidades arbitrárias (talvez você gostaria de contar em Gibibits!)

Exemplo:

>>> sizeof_fmt(168963795964)
'157.4GiB'

por Fred Cirera

Respondeu 07/07/2009 em 22:15
fonte usuário

votos
69

Uma biblioteca que tem todas as funcionalidades que parece que você está procurando humanize. humanize.naturalsize()parece estar a fazer tudo o que você está procurando.

Respondeu 18/03/2013 em 20:29
fonte usuário

votos
26

Aqui está a minha versão. Ele não usa um loop for. Tem complexidade constante, O ( 1 ), e é, em teoria, mais eficiente do que as respostas aqui que utilizam uma for-loop.

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'

Para torná-lo mais claro o que está acontecendo, podemos omitir o código para a formatação de strings. Aqui estão as linhas que realmente fazem o trabalho:

exponent = int(log(num, 1024))
quotient = num / 1024**exponent
unit_list[exponent]
Respondeu 16/04/2012 em 10:16
fonte usuário

votos
21

Enquanto eu sei que esta questão é antiga, recentemente surgiu com uma versão que evita loops, usando log2para determinar a ordem de tamanho, que funciona como uma mudança e um índice para a lista de sufixos:

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

Poderia muito bem ser considerado unpythonic para a sua legibilidade, embora :)

Respondeu 01/09/2014 em 22:23
fonte usuário

votos
9

Uma tal biblioteca é hurry.filesize .

>>> from hurry.filesize import alternative
>>> size(1, system=alternative)
'1 byte'
>>> size(10, system=alternative)
'10 bytes'
>>> size(1024, system=alternative)
'1 KB'
Respondeu 07/07/2009 em 22:00
fonte usuário

votos
7

Se você estiver usando Django instalado, você também pode tentar filesizeformat :

from django.template.defaultfilters import filesizeformat
filesizeformat(1073741824)

=>

"1.0 GB"
Respondeu 27/08/2014 em 13:47
fonte usuário

votos
7

Usando tanto poderes de 1000 ou kibibytes seria mais favorável ao padrão:

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 Nunca confie em uma biblioteca que imprime milhares com o sufixo (maiúsculas) K :)

Respondeu 21/05/2014 em 03:49
fonte usuário

votos
6

Riffing no fragmento fornecida como uma alternativa para hurry.filesize (), aqui é um fragmento que dá números de precisão variando com base no prefixo utilizado. Não é tão concisa como alguns trechos, mas eu gosto dos resultados.

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)
Respondeu 01/07/2011 em 12:40
fonte usuário

votos
5

Isso vai fazer o que você precisa em quase qualquer situação, é personalizável com argumentos opcionais, e como você pode ver, é muito muito autodocumentados:

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)

Exemplo de saída:

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

personalizações avançadas:

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

Este código é tanto Python 2 e Python 3 compatível. Cumprimento PEP8 é um exercício para o leitor. Lembre-se, é a saída que é bonito.

Atualizar:

Se você precisar de milhares de vírgulas, basta aplicar a extensão óbvia:

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

Por exemplo:

>>> pretty_units(987654321098765432109876543210)
'816,968.5 YiB'
Respondeu 02/07/2015 em 07:53
fonte usuário

votos
4

Há sempre tem que ser um daqueles caras. Bem, hoje sou eu. Aqui está uma solução one-liner - ou duas linhas se você contar a assinatura da função.

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
Respondeu 03/05/2017 em 03:09
fonte usuário

votos
4

Saindo da solução Sridhar Ratnakumar, eu gosto deste um pouco melhor. Funciona em Python 3.6+

def human_readable_size(size, decimal_places):
    for unit in ['','KB','MB','GB','TB']:
        if size < 1024.0:
            break
        size /= 1024.0
    return f"{size:.{decimal_places}f}{unit}"
Respondeu 29/04/2017 em 00:13
fonte usuário

votos
3

O projeto HumanFriendly ajuda com este .

import humanfriendly
humanfriendly.format_size(1024)

O código acima irá dar 1KB como resposta.
Exemplos podem ser encontrados aqui .

Respondeu 01/11/2018 em 21:00
fonte usuário

votos
3

Eu gosto da precisão fixa da versão decimal do senderle , então aqui está uma espécie de híbrido de que, com a resposta de joctee acima (você sabia que você poderia tomar registros com bases não inteiros?):

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')
Respondeu 19/07/2013 em 20:36
fonte usuário

votos
3

Desenho de todas as respostas anteriores, aqui está minha opinião sobre ele. É um objeto que irá armazenar o tamanho do arquivo em bytes como um inteiro. Mas quando você tenta imprimir o objeto, você receberá automaticamente uma versão legível.

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)
Respondeu 17/04/2012 em 16:47
fonte usuário

votos
2

Você deve usar "humanizar".

>>> humanize.naturalsize(1000000)
'1.0 MB'
>>> humanize.naturalsize(1000000, binary=True)
'976.6 KiB'
>>> humanize.naturalsize(1000000, gnu=True)
'976.6K'

Referência:

https://pypi.org/project/humanize/

Respondeu 06/09/2018 em 04:56
fonte usuário

votos
2

Como cerca de 2 forro simples:

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

Aqui está como ele funciona sob o capô:

  1. Calcula log 2 (tamanho)
  2. Divide-lo por 10 para obter a unidade mais próxima. (por exemplo, se o tamanho é de 5000 bytes, a unidade mais próxima é Kb, então a resposta deve ser X KiB)
  3. Retorna file_size/value_of_closest_unitjunto com a unidade.

No entanto, não funciona se o tamanho do arquivo é 0 ou negativo (porque o log é indefinido para 0 e números ve). Você pode adicionar verificações extras para eles:

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

Exemplos:

>>> humanizeFileSize(538244835492574234)
'478.06 PiB'
>>> humanizeFileSize(-924372537)
'881.55 MiB'
>>> humanizeFileSize(0)
'0 Bytes'

NOTA - Existe uma diferença entre Kb e KiB. KB significa 1000 bytes, enquanto KiB significa 1024 bytes. KB, MB, GB são todos múltiplos de 1000, enquanto que KiB, MiB, GiB etc são todos múltiplos de 1024. Mais sobre isso aqui

Respondeu 23/11/2014 em 21:39
fonte usuário

votos
2

DiveIntoPython3 também fala sobre essa função.

Respondeu 07/07/2009 em 22:44
fonte usuário

votos
1

Modern Django ter auto tag filesizeformat:

Formatos o valor como um human-readabletamanho de arquivo (ou seja, '13 KB', '4.1 MB', '102 bytes', etc.).

Por exemplo:

{{ value|filesizeformat }}

Se o valor for 123456789, a saída seria 117,7 MB.

Mais informações: https://docs.djangoproject.com/en/1.10/ref/templates/builtins/#filesizeformat

Respondeu 18/02/2017 em 15:53
fonte usuário

votos
1
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
Respondeu 02/02/2010 em 03:29
fonte usuário

votos
0

referem-se Sridhar Ratnakumar's resposta, actualizada para:

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)

e exemplo de saída é:

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
Respondeu 01/12/2018 em 02:02
fonte usuário

Cookies help us deliver our services. By using our services, you agree to our use of cookies. Learn more