从字节大小返回人类可读大小的函数:

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

如何做到这一点?


当前回答

我最近提出了一个避免循环的版本,使用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])

不过,它的可读性很可能被认为是非python化的。

其他回答

总有一个这样的人。今天轮到我了。这是一行代码——如果算上函数签名的话是两行。

def human_size(bytes, units=[' bytes','KB','MB','GB','TB', 'PB', 'EB']):
    """ Returns a human readable string representation 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

如果你需要大于1艾字节的大小,那就有点麻烦了:

def human_size(bytes, units=[' bytes','KB','MB','GB','TB', 'PB', 'EB']):
    return str(bytes) + units[0] if bytes < 1024 else human_size(bytes>>10, units[1:]) if units[1:] else f'{bytes>>10}ZB'

其中一个库是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'

为了以人类可读的形式获取文件大小,我创建了这个函数:

import os

def get_size(path):
    size = os.path.getsize(path)
    if size < 1024:
        return f"{size} bytes"
    elif size < pow(1024,2):
        return f"{round(size/1024, 2)} KB"
    elif size < pow(1024,3):
        return f"{round(size/(pow(1024,2)), 2)} MB"
    elif size < pow(1024,4):
        return f"{round(size/(pow(1024,3)), 2)} GB"
>>> get_size("a.txt")
1.4KB

一个拥有你所寻找的所有功能的库似乎是人性化的。Humanize.naturalsize()似乎可以做您所寻找的所有事情。

示例代码(python 3.10)

import humanize

disk_sizes_list = [1, 100, 999, 1000,1024, 2000,2048, 3000, 9999, 10000, 2048000000, 9990000000, 9000000000000000000000]
for size in disk_sizes_list:
    natural_size = humanize.naturalsize(size)
    binary_size = humanize.naturalsize(size, binary=True)
    print(f" {natural_size} \t| {binary_size}\t|{size}")

输出

 1 Byte     | 1 Byte    |1
 100 Bytes  | 100 Bytes |100
 999 Bytes  | 999 Bytes |999
 1.0 kB     | 1000 Bytes    |1000
 1.0 kB     | 1.0 KiB   |1024
 2.0 kB     | 2.0 KiB   |2000
 2.0 kB     | 2.0 KiB   |2048
 3.0 kB     | 2.9 KiB   |3000
 10.0 kB    | 9.8 KiB   |9999
 10.0 kB    | 9.8 KiB   |10000
 2.0 GB     | 1.9 GiB   |2048000000
 10.0 GB    | 9.3 GiB   |9990000000
 9.0 ZB     | 7.6 ZiB   |9000000000000000000000

这将在几乎任何情况下做你需要做的事情,是可选参数自定义的,正如你所看到的,几乎是自文档化的:

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'