可重复使用的库来获取人类可读的文件大小版本?

网上有各种各样的片断,会给你一个函数,从字节大小返回可读的大小:

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

但有没有一个Python库提供这个?

通过简单的实施来解决上述“需要图书馆的任务太小”的问题:

 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) 

支持:

  • 所有当前已知的二进制前缀
  • 负数和正数
  • 数字大于1000 Yobibytes
  • 任意单位(也许你喜欢用吉比西特计算!)

例:

 >>> sizeof_fmt(168963795964) '157.4GiB' 

由弗雷德Cirera

具有所有似乎你正在寻找的function的库是humanizehumanize.naturalsize()似乎做你正在寻找的一切。

这是我的版本。 它不使用for循环。 它具有不变的复杂性,O( 1 ),在理论上比这里使用for循环的答案更高效。

 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' 

为了更清楚地说明发生了什么,我们可以省略string格式化的代码。 以下是实际完成工作的线路:

 exponent = int(log(num, 1024)) quotient = num / 1024**exponent unit_list[exponent] 

虽然我知道这个问题是古老的,我最近想出了一个避免循环的版本,使用log2来确定作为一个class次加倍的大小顺序和索引到后缀列表中:

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

可以考虑unpythonic的可读性,虽然:)

一个这样的库是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' 

使用1000或kibibytes的function将更加标准友好:

 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永远不要相信用K(大写)后缀打印成千上万的图书馆:)

在作为hurry.filesize()的替代scheme提供的代码片段上进行Riffing,这里是一个片段,它根据所使用的前缀给出不同的精确数字。 它不像一些片段那么简单,但我喜欢结果。

 def human_size(size_bytes): """ format a size in bytes into a 'human' file size, eg bytes, KB, MB, GB, TB, PB Note that bytes/KB will be reported in whole numbers but MB and above will have greater precision eg 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) 

如果你正在使用Django安装,你也可以尝试filesizeformat :

 from django.template.defaultfilters import filesizeformat filesizeformat(1073741824) => "1.0 GB" 

这几乎可以在任何情况下完成你所需要的工作,可以用可选的参数进行定制,正如你所看到的,它几乎是自我logging的:

 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) 

示例输出:

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

高级自定义:

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

这段代码是兼容Python 2和Python 3的。 遵守PEP8是读者的一个练习。 请记住,这是可爱的输出

更新:

如果您需要数千个逗号,请使用明显的扩展名:

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

例如:

 >>> pretty_units(987654321098765432109876543210) '816,968.5 YiB' 

走Sridhar Ratnakumar解决scheme,我喜欢这个更好一点。 适用于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}" 

从所有以前的答案绘制,这是我的承担。 这是一个将文件大小以字节为单位存储为整数的对象。 但是,当您尝试打印对象时,会自动获取可读的版本。

 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) 

我喜欢senderle的十进制版本的固定精度,所以这里有一个与上面joctee的答案混合(你知道你可以采取非整数基地的日志?):

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

总是有那些家伙之一。 那么今天就是我。 这是一个单线解决scheme – 如果您计算function签名,则为两行。

 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 

DiveIntoPython3也谈到了这个function。

如何简单的2class轮:

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

以下是它如何工作:

  1. 计算log 2 (文件大小)
  2. 将其除以10以得到最接近的单位。 (例如,如果大小是5000字节,最接近的单位是Kb ,所以答案应该是X KiB)
  3. 返回file_size/value_of_closest_unit以及单位。

但是,如果文件大小为0或负数(因为日志未定义为0和-ve数字),则不起作用。 你可以添加额外的检查:

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

例子:

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

– Kb和KiB有所不同。 KB表示1000字节,而KiB表示1024字节。 KB,MB,GB都是1000的倍数,而KiB,MiB,GiB等都是1024的倍数。 更多关于它的信息

 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 

现代的Django有自我模板标签filesizeformat

格式化值像human-readable文件大小(即“13 KB”,“4.1 MB”,“102字节”等)。

例如:

 {{ value|filesizeformat }} 

如果值是123456789,输出将是117.7 MB。

更多信息: https : //docs.djangoproject.com/en/1.10/ref/templates/builtins/#filesizeformat