Estoy usando una biblioteca que lee un archivo y devuelve su tamaño en bytes.
Este tamaño de archivo se muestra al usuario final; para que sea más fácil para ellos entenderlo, estoy convirtiendo explícitamente el tamaño del archivo MB
dividiéndolo por 1024.0 * 1024.0
. Por supuesto, esto funciona, pero me pregunto si hay una mejor manera de hacer esto en Python.
Por mejor, me refiero a quizás una función stdlib que puede manipular tamaños de acuerdo con el tipo que quiero. Como si lo especifique MB
, automáticamente lo divide por 1024.0 * 1024.0
. Algo en estas líneas.
kB (Kilo) for 1.000 Byte
yKiB (Kibi) for 1.024 Byte
. Consulte en.wikipedia.org/wiki/Kibibyte .Respuestas:
Hay hurry.filesize que tomará el tamaño en bytes y hará una buena cadena si lo hace.
>>> from hurry.filesize import size >>> size(11000) '10K' >>> size(198283722) '189M'
O si desea 1K == 1000 (que es lo que asumen la mayoría de los usuarios):
>>> from hurry.filesize import size, si >>> size(11000, system=si) '11K' >>> size(198283722, system=si) '198M'
También tiene soporte IEC (pero eso no fue documentado):
>>> from hurry.filesize import size, iec >>> size(11000, system=iec) '10Ki' >>> size(198283722, system=iec) '189Mi'
Debido a que está escrito por Awesome Martijn Faassen, el código es pequeño, claro y extensible. Escribir sus propios sistemas es muy fácil.
Aqui hay uno:
mysystem = [ (1024 ** 5, ' Megamanys'), (1024 ** 4, ' Lotses'), (1024 ** 3, ' Tons'), (1024 ** 2, ' Heaps'), (1024 ** 1, ' Bunches'), (1024 ** 0, ' Thingies'), ]
Usado así:
>>> from hurry.filesize import size >>> size(11000, system=mysystem) '10 Bunches' >>> size(198283722, system=mysystem) '189 Heaps'
fuente
1024
(un int).MBFACTOR = float(1 << 20); mb= int(size_in_bytes) / MBFACTOR
@LennartRegebroEsto es lo que uso:
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: el tamaño debe enviarse en Bytes.
fuente
En lugar de un divisor de tamaño
1024 * 1024
, puede usar el<<
operador de desplazamiento bit a bit , es decir,1<<20
para obtener megabytes,1<<30
para obtener gigabytes, etc.En el escenario más simple que puede tener por ejemplo una constante
MBFACTOR = float(1<<20)
que puede ser utilizado con bytes, es decir:megas = size_in_bytes/MBFACTOR
.Los megabytes son generalmente todo lo que necesita, o de lo contrario se puede usar algo como esto:
# 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
fuente
>>
?0
.Aquí está la función compacta para calcular el tamaño
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])
Para obtener una salida más detallada y viceversa, consulte: http://code.activestate.com/recipes/578019-bytes-to-human-human-to-bytes-converter/
fuente
Consulte a continuación una forma rápida y relativamente fácil de leer para imprimir tamaños de archivo en una sola línea de código si ya sabe lo que desea. Estas frases sencillas combinan la gran respuesta de @ccpizza anterior con algunos trucos de formato útiles que leí aquí ¿Cómo imprimir números con comas como separadores de miles? .
Bytes
print ('{:,.0f}'.format(os.path.getsize(filepath))+" B")
Kilobits
print ('{:,.0f}'.format(os.path.getsize(filepath)/float(1<<7))+" kb")
Kilobytes
print ('{:,.0f}'.format(os.path.getsize(filepath)/float(1<<10))+" KB")
Megabits
print ('{:,.0f}'.format(os.path.getsize(filepath)/float(1<<17))+" mb")
Megabytes
print ('{:,.0f}'.format(os.path.getsize(filepath)/float(1<<20))+" MB")
Gigabits
print ('{:,.0f}'.format(os.path.getsize(filepath)/float(1<<27))+" gb")
Gigabytes
print ('{:,.0f}'.format(os.path.getsize(filepath)/float(1<<30))+" GB")
Terabytes
print ('{:,.0f}'.format(os.path.getsize(filepath)/float(1<<40))+" TB")
Obviamente, asumen que sabes aproximadamente con qué tamaño vas a tratar desde el principio, que en mi caso (editor de video en South West London TV) es MB y ocasionalmente GB para videos.
ACTUALIZAR USANDO PATHLIB En respuesta al comentario de Hildy, aquí está mi sugerencia para un par compacto de funciones (manteniendo las cosas 'atómicas' en lugar de fusionarlas) usando solo la biblioteca estándar de 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'
fuente
En caso de que alguien esté buscando el reverso de este problema (como yo lo hice), esto es lo que funciona para mí:
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
fuente
<< 10
a* 1024
,<< 20
a* 1024**2
y<< 30
a* 1024**3
.Aquí está:
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
fuente
Aquí mis dos centavos, que permite lanzar hacia arriba y hacia abajo, y agrega precisión personalizable:
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)
Agregue
TB
, etc., como desee.fuente
Aquí hay una versión que coincide con la salida de 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
fuente
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)
fuente
Aquí está mi implementación:
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)
Imprimirá hasta tres decimales y eliminará los ceros y puntos finales. El parámetro booleano
si
alternará el uso de una magnitud de tamaño basada en 10 frente a 2.Esta es su contraparte. Permite escribir archivos de configuración limpios como
{'maximum_filesize': from_filesize('10M')
. Devuelve un número entero que se aproxima al previsto. No estoy usando el cambio de bits porque el valor de origen es un número de punto flotante (lo aceptaráfrom_filesize('2.15M')
bien). Convertirlo en un entero / decimal funcionaría, pero hace que el código sea más complicado y ya funciona como está.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)
fuente
Aquí hay otra versión de la implementación inversa de @ romeo que maneja una sola cadena de entrada.
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)
fuente
Similar a la respuesta de Aaron Duke pero más "pitónico";)
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)
fuente
Soy nuevo en la programación. Se me ocurrió la siguiente función que convierte un tamaño de archivo determinado en un formato legible.
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]
fuente
Esto funciona correctamente para todos los tamaños de archivo:
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')))
fuente