可重用的库,以获得文件大小的人类可读版本?

Rei*_*ica 210 python filesize code-snippets

Web上有各种片段,可以为您提供从字节大小返回人类可读大小的功能:

>>> human_readable(2048)
'2 kilobytes'
>>>
Run Code Online (Sandbox Code Playgroud)

但是有没有提供这个的Python库?

Rei*_*ica 470

通过简单的实现解决上述"太小的任务需要库"问题:

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)
Run Code Online (Sandbox Code Playgroud)

支持:

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

例:

>>> sizeof_fmt(168963795964)
'157.4GiB'
Run Code Online (Sandbox Code Playgroud)

作者:Fred Cirera

  • 如果对这个"太小的任务"的所有迭代都被捕获并封装到带有测试的库中,那肯定会很好. (36认同)
  • 如果要增加小数组件的精度,请将第4行和第6行的"1"更改为所需的精度. (5认同)
  • @ MD004反过来说.定义前缀使得1 KB = 1000 B和1 KiB = 1024 B. (4认同)
  • 号码和单位之间应该有一个空格.如果要输出html或latex,它应该是一个非破坏性的空间. (3认同)
  • 只是一个想法,但对于除"B"以外的任何(?)后缀(即对于字节以外的单位),您希望因子为"1000.0"而不是"1024.0"否? (3认同)
  • 凉!我很喜欢它,我把它转换成Go lang:http://play.golang.org/p/68w_QCsE4F (3认同)
  • `sizeof_fmt(5)` 返回 `5.0B`。字节不应该有精度。 (2认同)

Pyr*_*ter 101

一个具有您正在寻找的所有功能的库humanize. humanize.naturalsize()似乎做你想要的一切.

  • 使用OP数据的一些例子:`humanize.naturalsize(2048)#=>'2.0 kB',`humanize.naturalsize(2048,binary = True)#=>'2.0 KiB'``manualize.naturalsize(2048 ,gnu = True)#=>'2.0K' (7认同)

joc*_*tee 30

这是我的版本.它不使用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'
Run Code Online (Sandbox Code Playgroud)

为了更清楚地说明发生了什么,我们可以省略字符串格式的代码.以下是实际完成工作的部分:

exponent = int(log(num, 1024))
quotient = num / 1024**exponent
unit_list[exponent]
Run Code Online (Sandbox Code Playgroud)

  • for循环的答案也是O(1),因为for循环是有界的 - 它们的计算时间不随输入的大小而缩放(我们没有无界的SI前缀). (28认同)
  • 请注意,在使用Python 3时,zip返回一个迭代器,因此您需要使用list()包装它。`unit_list = list(zip([''bytes','kB','MB','GB','TB','PB'],[0,0,1,2,2,2])) (3认同)
  • 当你谈到优化这么短的代码时,为什么不使用if/elif/else?最后一次检查num == 1是不必要的,除非你期望负文件大小.否则:干得好,我喜欢这个版本. (2认同)
  • 我的代码肯定会更加优化.但是,我的观点是证明这项任务可以通过不断的复杂性来解决. (2认同)

aka*_*IOT 24

虽然我知道这个问题是古老的,但我最近提出了一个避免循环的版本,log2用于确定大小顺序,该大小顺序兼作移位和后缀列表的索引:

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])
Run Code Online (Sandbox Code Playgroud)

尽管如此:)可以被认为是unpythonic的可读性


wp-*_*com 16

关于Sridhar Ratnakumar解决方案,我更喜欢这个.适用于Python 3.6+

def human_readable_size(size, decimal_places=3):
    for unit in ['B','KiB','MiB','GiB','TiB']:
        if size < 1024.0:
            break
        size /= 1024.0
    return f"{size:.{decimal_places}f}{unit}"
Run Code Online (Sandbox Code Playgroud)


Jon*_*sen 14

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

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

=>

"1.0 GB"
Run Code Online (Sandbox Code Playgroud)

  • 对我来说,这样做的一个缺点是它使用 GB 而不是 GiB,尽管它除以 1024。 (2认同)

wp-*_*com 14

总是有一个人.那么今天是我.这是一个单线解决方案 - 如果计算功能签名,则为两行.

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:])
Run Code Online (Sandbox Code Playgroud)

>>> human_size(123)
123 bytes
>>> human_size(123456789)
117GB
Run Code Online (Sandbox Code Playgroud)

  • @ImanolEizaguirre最佳实践将指出,按照您的建议进行操作是个好主意,因此请不要在无意中将错误引入程序中。但是,编写此函数是安全的,因为决不会操纵单位列表。如果对其进行了操作,则更改将是永久的,并且任何后续函数调用都将收到列表的经过处理的版本,作为unites参数的默认参数。 (3认同)
  • 仅供参考,输出将始终向下舍入。 (2认同)
  • 对于 Python 3,如果您想要小数点,请使用以下代码: ``` def human_size(fsize,units=['bytes','KB','MB','GB','TB','PB', 'EB']): 返回 "{:.2f}{}".format(float(fsize),units[0]) if fsize &lt; 1024 else human_size(fsize / 1024,units[1:]) ``` (2认同)

Rei*_*ica 9

一个这样的库是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'
Run Code Online (Sandbox Code Playgroud)

  • 但是,这个库不是很容易定制的.>>>来自hurry.filesize导入尺寸>>>尺寸(1031053)>>>尺寸(3033053)'2M'我希望它显示,例如,'2.4M'或'2423K'..而不是公然近似' 2M". (3认同)

Gia*_*lli 9

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

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)
Run Code Online (Sandbox Code Playgroud)

PS永远不要相信使用K(大写)后缀打印数千的库


小智 7

HumanFriendly 项目对此有所帮助。

import humanfriendly
humanfriendly.format_size(1024)
Run Code Online (Sandbox Code Playgroud)

上面的代码将给出 1KB 作为答案。可以在此处找到
示例。


小智 6

在作为hurry.filesize()的替代提供的片段上重复,这里是一个片段,根据使用的前缀提供不同的精度数字.它不像一些片段那样简洁,但我喜欢结果.

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)
Run Code Online (Sandbox Code Playgroud)


goj*_*omo 6

这几乎可以在任何情况下完成所需,可以使用可选参数进行自定义,正如您所看到的,几乎是自我记录的:

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)
Run Code Online (Sandbox Code Playgroud)

示例输出:

>>> 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'
Run Code Online (Sandbox Code Playgroud)

高级自定义:

>>> 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'
Run Code Online (Sandbox Code Playgroud)

此代码兼容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))
Run Code Online (Sandbox Code Playgroud)

例如:

>>> pretty_units(987654321098765432109876543210)
'816,968.5 YiB'
Run Code Online (Sandbox Code Playgroud)


Sae*_*odi 5

您应该使用“人性化”。

>>> humanize.naturalsize(1000000)
'1.0 MB'
>>> humanize.naturalsize(1000000, binary=True)
'976.6 KiB'
>>> humanize.naturalsize(1000000, gnu=True)
'976.6K'
Run Code Online (Sandbox Code Playgroud)

参考:

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