获取文件大小的人类可读版本

发布于 2024-07-26 12:44:50 字数 150 浏览 5 评论 0原文

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

>>> human_readable(2048)
'2 kilobytes'

我该怎么做?

A function to return a human-readable size from the bytes size:

>>> human_readable(2048)
'2 kilobytes'

How can I do this?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(30

亽野灬性zι浪 2024-08-02 12:44:50

通过简单的实现(使用 f 字符串,因此 Python 3.6+)解决上述“任务太小,不需要库”问题:

def sizeof_fmt(num, suffix="B"):
    for unit in ("", "Ki", "Mi", "Gi", "Ti", "Pi", "Ei", "Zi"):
        if abs(num) < 1024.0:
            return f"{num:3.1f}{unit}{suffix}"
        num /= 1024.0
    return f"{num:.1f}Yi{suffix}"

支持:

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

示例:

>>> sizeof_fmt(168963795964)
'157.4GiB'

通过 弗雷德·西雷拉

Addressing the above "too small a task to require a library" issue by a straightforward implementation (using f-strings, so Python 3.6+):

def sizeof_fmt(num, suffix="B"):
    for unit in ("", "Ki", "Mi", "Gi", "Ti", "Pi", "Ei", "Zi"):
        if abs(num) < 1024.0:
            return f"{num:3.1f}{unit}{suffix}"
        num /= 1024.0
    return f"{num:.1f}Yi{suffix}"

Supports:

  • all currently known binary prefixes
  • negative and positive numbers
  • numbers larger than 1000 Yobibytes
  • arbitrary units (maybe you like to count in Gibibits!)

Example:

>>> sizeof_fmt(168963795964)
'157.4GiB'

by Fred Cirera

流云如水 2024-08-02 12:44:50

具有您正在寻找的所有功能的库是 humanize humanize.naturalsize() 似乎可以完成您正在寻找的一切。

示例代码 (Python3.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

A library that has all the functionality that it seems you're looking for is humanize. humanize.naturalsize() seems to do everything you're looking for.

Example code (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}")

Output

 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
音盲 2024-08-02 12:44:50

在我看来,以下内容适用于 Python 3.6+,是这里最容易理解的答案,并且允许您自定义使用的小数位数。

def human_readable_size(size, decimal_places=2):
    for unit in ['B', 'KiB', 'MiB', 'GiB', 'TiB', 'PiB']:
        if size < 1024.0 or unit == 'PiB':
            break
        size /= 1024.0
    return f"{size:.{decimal_places}f} {unit}"

The following works in Python 3.6+, is, in my opinion, the easiest to understand answer on here, and lets you customize the amount of decimal places used.

def human_readable_size(size, decimal_places=2):
    for unit in ['B', 'KiB', 'MiB', 'GiB', 'TiB', 'PiB']:
        if size < 1024.0 or unit == 'PiB':
            break
        size /= 1024.0
    return f"{size:.{decimal_places}f} {unit}"
欢烬 2024-08-02 12:44:50

总得有这样的人之一。 好吧,今天是我。 这是一行——如果算上函数签名的话,可以是两行。

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

如果您需要的大小大于艾字节,那就有点粗糙了:

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'

There's always got to be one of those guys. Well today it's me. Here's a one-liner -- or two lines if you count the function signature.

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

If you need sizes bigger than an Exabyte, it's a little bit more gnarly:

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'
梦境 2024-08-02 12:44:50

这是我的版本。 它不使用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'

为了更清楚地了解发生了什么,我们可以省略字符串格式化的代码。 以下是实际完成工作的几行代码:

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

Here's my version. It does not use a for loop. It has constant complexity, O(1), and is in theory more efficient than the answers here that use a 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'

To make it more clear what is going on, we can omit the code for the string formatting. Here are the lines that actually do the work:

exponent = int(log(num, 1024))
quotient = num / 1024**exponent
unit_list[exponent]
姐不稀罕 2024-08-02 12:44:50

我最近提出了一个避免循环的版本,使用 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 maximum 3 decimals, and should never resort
    # to exponent values)
    return '{:.4g} {}'.format(size / (1 << (order * 10)), _suffixes[order])

不过,由于其可读性,它很可能被认为是非Pythonic的。

I recently came up with a version that avoids loops, using log2 to determine the size order which doubles as a shift and an index into the suffix list:

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 maximum 3 decimals, and should never resort
    # to exponent values)
    return '{:.4g} {}'.format(size / (1 << (order * 10)), _suffixes[order])

It could well be considered unpythonic for its readability, though.

£烟消云散 2024-08-02 12:44:50

如果您使用的是 Django,还可以尝试 filesizeformat

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

=>

"1.0 GB"

If you're using Django, you can also try filesizeformat:

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

=>

"1.0 GB"
甜味拾荒者 2024-08-02 12:44:50

你应该使用“人性化”。

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

参考:

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

You should use "humanize".

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

Reference:

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

百善笑为先 2024-08-02 12:44:50

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

One such library is 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'
沙与沫 2024-08-02 12:44:50

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

PS 永远不要信任打印的库数千个带有 K(大写)后缀的:)

Using either powers of 1000 or kibibytes would be more standard-friendly:

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)

P.S. Never trust a library that prints thousands with the K (uppercase) suffix :)

故事与诗 2024-08-02 12:44:50

这几乎可以满足您在任何情况下的需要,可以使用可选参数进行自定义,并且如您所见,它是相当的自我文档化:

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

This will do what you need in almost any situation, is customizable with optional arguments, and as you can see, is pretty much self-documenting:

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)

Example output:

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

Advanced customizations:

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

This code is both Python 2 and Python 3 compatible. PEP8 compliance is an exercise for the reader. Remember, it's the output that's pretty.

Update:

If you need thousands commas, just apply the obvious extension:

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

For example:

>>> pretty_units(987654321098765432109876543210)
'816,968.5 YiB'
我ぃ本無心為│何有愛 2024-08-02 12:44:50

HumanFriendly 项目可以帮助解决这个问题

import humanfriendly
humanfriendly.format_size(1024)

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

The HumanFriendly project helps with this.

import humanfriendly
humanfriendly.format_size(1024)

The above code will give 1KB as the answer.
Examples can be found here.

拔了角的鹿 2024-08-02 12:44:50

翻阅作为 rush.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)

Riffing on the snippet provided as an alternative to hurry.filesize(), here is a snippet that gives varying precision numbers based on the prefix used. It isn't as terse as some snippets, but I like the results.

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)
裸钻 2024-08-02 12:44:50

根据之前的所有答案,这是我的看法。 它是一个将文件大小(以字节为单位)存储为整数的对象。 但是当您尝试打印该对象时,您会自动获得人类可读的版本。

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)

Drawing from all the previous answers, here is my take on it. It's an object which will store the file size in bytes as an integer. But when you try to print the object, you automatically get a human readable version.

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)
旧时浪漫 2024-08-02 12:44:50

现代 Django 有自我模板标签 filesizeformat

将值格式化为人类可读 文件大小(即“13 KB”、“4.1 MB”、“102 字节”等) .)。

例如:

{{ value|filesizeformat }}

如果值为 123456789,则输出将为 117.7 MB。

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

Modern Django have self template tag filesizeformat:

Formats the value like a human-readable file size (i.e. '13 KB', '4.1 MB', '102 bytes', etc.).

For example:

{{ value|filesizeformat }}

If value is 123456789, the output would be 117.7 MB.

More info: https://docs.djangoproject.com/en/1.10/ref/templates/builtins/#filesizeformat

朱染 2024-08-02 12:44:50

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

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

To get the file size in a human readable form, I created this function:

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
简单 2024-08-02 12:44:50

我喜欢 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')

I like the fixed precision of senderle's decimal version, so here's a sort of hybrid of that with joctee's answer above (did you know you could take logs with non-integer bases?):

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')
行至春深 2024-08-02 12:44:50

这是一个 oneliner lambda,没有任何导入来转换为人类可读的文件大小。 传递以字节为单位的值。

to_human = lambda v : str(v >> ((max(v.bit_length()-1, 0)//10)*10)) +["", "K", "M", "G", "T", "P", "E"][max(v.bit_length()-1, 0)//10]
>>> to_human(1024)
'1K'
>>> to_human(1024*1024*3)
'3M'

Here is an oneliner lambda without any imports to convert to human readable filesize. Pass the value in bytes.

to_human = lambda v : str(v >> ((max(v.bit_length()-1, 0)//10)*10)) +["", "K", "M", "G", "T", "P", "E"][max(v.bit_length()-1, 0)//10]
>>> to_human(1024)
'1K'
>>> to_human(1024*1024*3)
'3M'
热血少△年 2024-08-02 12:44:50

一个简单的 2 衬垫怎么样:

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. 计算 log2(filesize)
  2. 将其除以 10 以获得最接近的单位。 (例如,如果大小为 5000 字节,则最接近的单位为 Kb,因此答案应为 X KiB)
  3. 返回 file_size/value_of_closest_unit 以及单位。

但是,如果文件大小为 0 或负数,则它不起作用(因为 log 对于 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 的倍数。 更多信息请点击这里

How about a simple 2 liner:

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

Here is how it works under the hood:

  1. Calculates log2(filesize)
  2. Divides it by 10 to get the closest unit. (eg if size is 5000 bytes, the closest unit is Kb, so the answer should be X KiB)
  3. Returns file_size/value_of_closest_unit along with unit.

It however doesn't work if filesize is 0 or negative (because log is undefined for 0 and -ve numbers). You can add extra checks for them:

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

Examples:

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

NOTE - There is a difference between Kb and KiB. KB means 1000 bytes, whereas KiB means 1024 bytes. KB,MB,GB are all multiples of 1000, whereas KiB, MiB, GiB etc are all multiples of 1024. More about it here

但可醉心 2024-08-02 12:44:50

您在下面找到的绝不是已发布的解决方案中性能最好或最短的解决方案。 相反,它专注于许多其他答案都忽略的一个特定问题

即当给出像 999_995 这样的输入时的情况:

Python 3.6.1 ...
...
>>> value = 999_995
>>> base = 1000
>>> math.log(value, base)
1.999999276174054

被截断为最接近的整数并应用回输入给出

>>> order = int(math.log(value, base))
>>> value/base**order
999.995

这似乎正是我们所期望的,直到我们需要控制 <强>输出精度。 这就是事情开始变得有点困难的时候。

将精度设置为 2 位数字后,我们得到:

>>> round(value/base**order, 2)
1000 # K

而不是 1M

我们如何应对这个问题?

当然,我们可以明确地检查它:

if round(value/base**order, 2) == base:
    order += 1

但是我们可以做得更好吗? 在执行最后一步之前,我们能否知道应该以哪种方式切割订单

事实证明我们可以。

假设0.5位小数舍入规则,上述if条件转换为:

在此处输入图像描述

导致

def abbreviate(value, base=1000, precision=2, suffixes=None):
    if suffixes is None:
        suffixes = ['', 'K', 'M', 'B', 'T']

    if value == 0:
        return f'{0}{suffixes[0]}'

    order_max = len(suffixes) - 1
    order = log(abs(value), base)
    order_corr = order - int(order) >= log(base - 0.5/10**precision, base)
    order = min(int(order) + order_corr, order_max)

    factored = round(value/base**order, precision)

    return f'{factored:,g}{suffixes[order]}'

给出

>>> abbreviate(999_994)
'999.99K'
>>> abbreviate(999_995)
'1M'
>>> abbreviate(999_995, precision=3)
'999.995K'
>>> abbreviate(2042, base=1024)
'1.99K'
>>> abbreviate(2043, base=1024)
'2K'

What you're about to find below is by no means the most performant or shortest solution among the ones already posted. Instead, it focuses on one particular issue that many of the other answers miss.

Namely the case when input like 999_995 is given:

Python 3.6.1 ...
...
>>> value = 999_995
>>> base = 1000
>>> math.log(value, base)
1.999999276174054

which, being truncated to the nearest integer and applied back to the input gives

>>> order = int(math.log(value, base))
>>> value/base**order
999.995

This seems to be exactly what we'd expect until we're required to control output precision. And this is when things start to get a bit difficult.

With the precision set to 2 digits we get:

>>> round(value/base**order, 2)
1000 # K

instead of 1M.

How can we counter that?

Of course, we can check for it explicitly:

if round(value/base**order, 2) == base:
    order += 1

But can we do better? Can we get to know which way the order should be cut before we do the final step?

It turns out we can.

Assuming 0.5 decimal rounding rule, the above if condition translates into:

enter image description here

resulting in

def abbreviate(value, base=1000, precision=2, suffixes=None):
    if suffixes is None:
        suffixes = ['', 'K', 'M', 'B', 'T']

    if value == 0:
        return f'{0}{suffixes[0]}'

    order_max = len(suffixes) - 1
    order = log(abs(value), base)
    order_corr = order - int(order) >= log(base - 0.5/10**precision, base)
    order = min(int(order) + order_corr, order_max)

    factored = round(value/base**order, precision)

    return f'{factored:,g}{suffixes[order]}'

giving

>>> abbreviate(999_994)
'999.99K'
>>> abbreviate(999_995)
'1M'
>>> abbreviate(999_995, precision=3)
'999.995K'
>>> abbreviate(2042, base=1024)
'1.99K'
>>> abbreviate(2043, base=1024)
'2K'
痴意少年 2024-08-02 12:44:50

在这里你有它:

def humanSize(value, decimals=2, scale=1024, units=("B", "kiB", "MiB", "GiB", "TiB", "PiB", "EiB", "ZiB", "YiB", "RiB", "QiB")):
    for unit in units:
        if value < scale:
            break
        value /= scale
    if int(value) == value:
        # do not return decimals, if the value is already round
        return int(value), unit
    return round(value * 10**decimals) / 10**decimals, unit

最正确的格式:

f"{humanSize(os.path.getsize(path))[0]}\u202f{humanSize(os.path.getsize(path))[1]}"

示例:

>>> humanSize(42)
(42, 'B')
>>> humanSize(9137017301)
(8.51, 'GiB')
>>> humanSize(4096)
(4, 'kiB')
>>> humanSize(1267650600228229401496703205376)
(1, 'QiB')
>>> humanSize(543864)
(531.12, 'kiB')
>>> humanSize(500000000000)
(465.66, 'GiB')

Here you have it:

def humanSize(value, decimals=2, scale=1024, units=("B", "kiB", "MiB", "GiB", "TiB", "PiB", "EiB", "ZiB", "YiB", "RiB", "QiB")):
    for unit in units:
        if value < scale:
            break
        value /= scale
    if int(value) == value:
        # do not return decimals, if the value is already round
        return int(value), unit
    return round(value * 10**decimals) / 10**decimals, unit

Most correct format:

f"{humanSize(os.path.getsize(path))[0]}\u202f{humanSize(os.path.getsize(path))[1]}"

Examples:

>>> humanSize(42)
(42, 'B')
>>> humanSize(9137017301)
(8.51, 'GiB')
>>> humanSize(4096)
(4, 'kiB')
>>> humanSize(1267650600228229401496703205376)
(1, 'QiB')
>>> humanSize(543864)
(531.12, 'kiB')
>>> humanSize(500000000000)
(465.66, 'GiB')
第几種人 2024-08-02 12:44:50

如果有人想知道,请转换 Sridhar Ratnakumar 的回答回到字节,您可以执行以下操作:

import math

def format_back_to_bytes(value):
    for power, unit in enumerate(["", "Ki", "Mi", "Gi", "Ti", "Pi", "Ei", "Zi"]):
        if value[-3:-1] == unit:
            return round(float(value[:-3])*math.pow(2, 10*power))

用法:

>>> format_back_to_bytes('212.4GiB')
228062763418

In case someone is wondering, to convert Sridhar Ratnakumar's answer back to bytes you could do the following:

import math

def format_back_to_bytes(value):
    for power, unit in enumerate(["", "Ki", "Mi", "Gi", "Ti", "Pi", "Ei", "Zi"]):
        if value[-3:-1] == unit:
            return round(float(value[:-3])*math.pow(2, 10*power))

Usage:

>>> format_back_to_bytes('212.4GiB')
228062763418
蘑菇王子 2024-08-02 12:44:50
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
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
疯狂的代价 2024-08-02 12:44:50

如果 Boltons 中提供此功能,这是一个非常好的大多数项目都可以使用的方便库。

>>> bytes2human(128991)
'126K'
>>> bytes2human(100001221)
'95M'
>>> bytes2human(0, 2)
'0.00B'

This feature if available in Boltons which is a very handy library to have for most projects.

>>> bytes2human(128991)
'126K'
>>> bytes2human(100001221)
'95M'
>>> bytes2human(0, 2)
'0.00B'
×纯※雪 2024-08-02 12:44:50

这是我为不同问题写的东西......

很像xApple答案,该对象将始终以人类可读的方式打印格式。 不同之处在于它也是一个正确的 int,因此您可以用它进行数学运算!
它将格式说明符直接传递到数字格式并附加后缀,因此几乎可以保证请求的长度将超出两个或三个字符。 我从未使用过这段代码,所以我没有费心去修复它!


class ByteSize(int):

    _KB = 1024
    _suffixes = 'B', 'KB', 'MB', 'GB', 'PB'

    def __new__(cls, *args, **kwargs):
        return super().__new__(cls, *args, **kwargs)

    def __init__(self, *args, **kwargs):
        self.bytes = self.B = int(self)
        self.kilobytes = self.KB = self / self._KB**1
        self.megabytes = self.MB = self / self._KB**2
        self.gigabytes = self.GB = self / self._KB**3
        self.petabytes = self.PB = self / self._KB**4
        *suffixes, last = self._suffixes
        suffix = next((
            suffix
            for suffix in suffixes
            if 1 < getattr(self, suffix) < self._KB
        ), last)
        self.readable = suffix, getattr(self, suffix)

        super().__init__()

    def __str__(self):
        return self.__format__('.2f')

    def __repr__(self):
        return '{}({})'.format(self.__class__.__name__, super().__repr__())

    def __format__(self, format_spec):
        suffix, val = self.readable
        return '{val:{fmt}} {suf}'.format(val=val, fmt=format_spec, suf=suffix)

    def __sub__(self, other):
        return self.__class__(super().__sub__(other))

    def __add__(self, other):
        return self.__class__(super().__add__(other))
    
    def __mul__(self, other):
        return self.__class__(super().__mul__(other))

    def __rsub__(self, other):
        return self.__class__(super().__sub__(other))

    def __radd__(self, other):
        return self.__class__(super().__add__(other))
    
    def __rmul__(self, other):
        return self.__class__(super().__rmul__(other))   

用法:

>>> size = 6239397620
>>> print(size)
5.81 GB
>>> size.GB
5.810891855508089
>>> size.gigabytes
5.810891855508089
>>> size.PB
0.005674699077644618
>>> size.MB
5950.353260040283
>>> size
ByteSize(6239397620)

Here's something I wrote for a different question...

Much like xApple's answer, this object will always print in a human-readable format. The difference is that it's also a proper int, so you can do math with it!
It passes the format specifier straight through to the number format and tacks on the suffix, so it's pretty much guaranteed that the requested length will be exceeded by two or three characters. I've never had a use for this code, so I haven't bothered to fix it!


class ByteSize(int):

    _KB = 1024
    _suffixes = 'B', 'KB', 'MB', 'GB', 'PB'

    def __new__(cls, *args, **kwargs):
        return super().__new__(cls, *args, **kwargs)

    def __init__(self, *args, **kwargs):
        self.bytes = self.B = int(self)
        self.kilobytes = self.KB = self / self._KB**1
        self.megabytes = self.MB = self / self._KB**2
        self.gigabytes = self.GB = self / self._KB**3
        self.petabytes = self.PB = self / self._KB**4
        *suffixes, last = self._suffixes
        suffix = next((
            suffix
            for suffix in suffixes
            if 1 < getattr(self, suffix) < self._KB
        ), last)
        self.readable = suffix, getattr(self, suffix)

        super().__init__()

    def __str__(self):
        return self.__format__('.2f')

    def __repr__(self):
        return '{}({})'.format(self.__class__.__name__, super().__repr__())

    def __format__(self, format_spec):
        suffix, val = self.readable
        return '{val:{fmt}} {suf}'.format(val=val, fmt=format_spec, suf=suffix)

    def __sub__(self, other):
        return self.__class__(super().__sub__(other))

    def __add__(self, other):
        return self.__class__(super().__add__(other))
    
    def __mul__(self, other):
        return self.__class__(super().__mul__(other))

    def __rsub__(self, other):
        return self.__class__(super().__sub__(other))

    def __radd__(self, other):
        return self.__class__(super().__add__(other))
    
    def __rmul__(self, other):
        return self.__class__(super().__rmul__(other))   

Usage:

>>> size = 6239397620
>>> print(size)
5.81 GB
>>> size.GB
5.810891855508089
>>> size.gigabytes
5.810891855508089
>>> size.PB
0.005674699077644618
>>> size.MB
5950.353260040283
>>> size
ByteSize(6239397620)
归途 2024-08-02 12:44:50

这是 的基于类的变体对于我们这些喜欢强类型的人来说,Fred Cirera 的回答

class Unit(int):
    multiplier = 1000
    precision = 2
    prefixes = ('', 'k')
    unit = '?'

    def __str__(self):
        number = self
        for prefix in self.prefixes:
            if number < self.multiplier or prefix == self.prefixes[-1]:
                break
            number /= float(self.multiplier)
        if prefix:
            return f'{number:.{self.precision}f}{prefix}{self.unit}'
        return f'{int(number)}{self.unit}'


class Filesize(Unit):
    multiplier = 1024
    prefixes = ('', 'Ki', 'Mi', 'Gi', 'Ti', 'Pi', 'Ei', 'Zi', 'Yi')
    unit = 'B'

class Distance(Unit):
    unit = 'm'


# Prints 123m
print(Distance(123))

# Prints 123456.8km
print(Distance(123456789))

Here is a class-based variant of Fred Cirera's answer, for those of us who prefer strong typing:

class Unit(int):
    multiplier = 1000
    precision = 2
    prefixes = ('', 'k')
    unit = '?'

    def __str__(self):
        number = self
        for prefix in self.prefixes:
            if number < self.multiplier or prefix == self.prefixes[-1]:
                break
            number /= float(self.multiplier)
        if prefix:
            return f'{number:.{self.precision}f}{prefix}{self.unit}'
        return f'{int(number)}{self.unit}'


class Filesize(Unit):
    multiplier = 1024
    prefixes = ('', 'Ki', 'Mi', 'Gi', 'Ti', 'Pi', 'Ei', 'Zi', 'Yi')
    unit = 'B'

class Distance(Unit):
    unit = 'm'


# Prints 123m
print(Distance(123))

# Prints 123456.8km
print(Distance(123456789))
盗琴音 2024-08-02 12:44:50

这是 joctee 实现的替代版本,已更新为使用 Python 3 语法并将否定作为例外情况处理。

我添加了类型和文档,并在收到负数作为输入时引发错误。

#!/usr/bin/env python3
from math import log
from typing import List, Tuple

def format_size(size: int) -> str:
    """
    Convert a file size to a human-friendly format.

    Parameters:
    size (int): The file size in bytes.

    Returns:
    str: The human-friendly format of the file size.

    Raises:
    ValueError: If size is negative.
    """
    units: List[Tuple[str, int]] = [
        ("bytes", 0),
        ("kB", 0),
        ("MB", 1),
        ("GB", 2),
        ("TB", 2),
        ("PB", 2)
    ]
    
    if size < 0:
        raise ValueError("Negative size not allowed")
    if size == 0:
        return "0 bytes"
    if size == 1:
        return "1 byte"
    
    exponent = min(int(log(size, 1024)), len(units) - 1)
    quotient = float(size) / 1024**exponent
    unit, precision = units[exponent]
    return f"{quotient:.{precision}f} {unit}"

下面是一个更简洁的迭代版本:

def format_size(size: int) -> str:
    if size < 0:
        raise ValueError("Negative size not allowed")
    for unit in ["bytes", "KB", "MB", "GB", "TB", "PB"]:
        if size < 1024.0:
            return f"{size:.2f} {unit}"
        size /= 1024.0

用法

下面是 format_size 函数的一些用法示例:

#!/usr/bin/env python3
from file_size_formatter import format_size

# Constants for file size units
KILOBYTE = 1024                 # 1,024 bytes
MEGABYTE = KILOBYTE * KILOBYTE  # 1,048,576 bytes
GIGABYTE = KILOBYTE * MEGABYTE  # 1,073,741,824 bytes
TERABYTE = KILOBYTE * GIGABYTE  # 1,099,511,627,776 bytes
PETABYTE = KILOBYTE * TERABYTE  # 1,125,899,906,842,624 bytes

def main():
    # Examples of usage:
    print(format_size(0))         # Output: '0 bytes'
    print(format_size(1))         # Output: '1 byte'
    print(format_size(KILOBYTE))  # Output: '1 kB'
    print(format_size(MEGABYTE))  # Output: '1.0 MB'
    print(format_size(GIGABYTE))  # Output: '1.00 GB'
    print(format_size(TERABYTE))  # Output: '1.00 TB'
    print(format_size(PETABYTE))  # Output: '1.00 PB'

    # Example with negative input
    try:
        print(format_size(-1024))  # This will raise a ValueError
    except ValueError as e:
        print(e)  # Output: 'Negative size not allowed'

if __name__ == "__main__":
    main()

PyTest

下面是一个测试套件,用于验证 format_size 函数的输出:

#!/usr/bin/env python3
import pytest
from file_size_formatter import format_size

# Constants for file size units
KILOBYTE = 1024                 # 1,024 bytes
MEGABYTE = KILOBYTE * KILOBYTE  # 1,048,576 bytes
GIGABYTE = KILOBYTE * MEGABYTE  # 1,073,741,824 bytes
TERABYTE = KILOBYTE * GIGABYTE  # 1,099,511,627,776 bytes
PETABYTE = KILOBYTE * TERABYTE  # 1,125,899,906,842,624 bytes

def test_format_size():
    assert format_size(0) == "0 bytes"
    assert format_size(1) == "1 byte"
    assert format_size(KILOBYTE) == "1 kB"
    assert format_size(MEGABYTE) == "1.0 MB"
    assert format_size(GIGABYTE) == "1.00 GB"
    assert format_size(TERABYTE) == "1.00 TB"
    assert format_size(PETABYTE) == "1.00 PB"

def test_format_size_negative():
    with pytest.raises(ValueError, match="Negative size not allowed"):
        format_size(-1024)

Here is an alternate version of joctee's implementation updated to use Python 3 syntax and handle negatives as exceptional cases.

I added types and docs, as well as raising an error upon receiving a negative number as input.

#!/usr/bin/env python3
from math import log
from typing import List, Tuple

def format_size(size: int) -> str:
    """
    Convert a file size to a human-friendly format.

    Parameters:
    size (int): The file size in bytes.

    Returns:
    str: The human-friendly format of the file size.

    Raises:
    ValueError: If size is negative.
    """
    units: List[Tuple[str, int]] = [
        ("bytes", 0),
        ("kB", 0),
        ("MB", 1),
        ("GB", 2),
        ("TB", 2),
        ("PB", 2)
    ]
    
    if size < 0:
        raise ValueError("Negative size not allowed")
    if size == 0:
        return "0 bytes"
    if size == 1:
        return "1 byte"
    
    exponent = min(int(log(size, 1024)), len(units) - 1)
    quotient = float(size) / 1024**exponent
    unit, precision = units[exponent]
    return f"{quotient:.{precision}f} {unit}"

Here is a more terse, iterative version:

def format_size(size: int) -> str:
    if size < 0:
        raise ValueError("Negative size not allowed")
    for unit in ["bytes", "KB", "MB", "GB", "TB", "PB"]:
        if size < 1024.0:
            return f"{size:.2f} {unit}"
        size /= 1024.0

Usage

Here is some example of usage for the format_size function:

#!/usr/bin/env python3
from file_size_formatter import format_size

# Constants for file size units
KILOBYTE = 1024                 # 1,024 bytes
MEGABYTE = KILOBYTE * KILOBYTE  # 1,048,576 bytes
GIGABYTE = KILOBYTE * MEGABYTE  # 1,073,741,824 bytes
TERABYTE = KILOBYTE * GIGABYTE  # 1,099,511,627,776 bytes
PETABYTE = KILOBYTE * TERABYTE  # 1,125,899,906,842,624 bytes

def main():
    # Examples of usage:
    print(format_size(0))         # Output: '0 bytes'
    print(format_size(1))         # Output: '1 byte'
    print(format_size(KILOBYTE))  # Output: '1 kB'
    print(format_size(MEGABYTE))  # Output: '1.0 MB'
    print(format_size(GIGABYTE))  # Output: '1.00 GB'
    print(format_size(TERABYTE))  # Output: '1.00 TB'
    print(format_size(PETABYTE))  # Output: '1.00 PB'

    # Example with negative input
    try:
        print(format_size(-1024))  # This will raise a ValueError
    except ValueError as e:
        print(e)  # Output: 'Negative size not allowed'

if __name__ == "__main__":
    main()

PyTest

Here is a test suite that verifies the output of the format_size function:

#!/usr/bin/env python3
import pytest
from file_size_formatter import format_size

# Constants for file size units
KILOBYTE = 1024                 # 1,024 bytes
MEGABYTE = KILOBYTE * KILOBYTE  # 1,048,576 bytes
GIGABYTE = KILOBYTE * MEGABYTE  # 1,073,741,824 bytes
TERABYTE = KILOBYTE * GIGABYTE  # 1,099,511,627,776 bytes
PETABYTE = KILOBYTE * TERABYTE  # 1,125,899,906,842,624 bytes

def test_format_size():
    assert format_size(0) == "0 bytes"
    assert format_size(1) == "1 byte"
    assert format_size(KILOBYTE) == "1 kB"
    assert format_size(MEGABYTE) == "1.0 MB"
    assert format_size(GIGABYTE) == "1.00 GB"
    assert format_size(TERABYTE) == "1.00 TB"
    assert format_size(PETABYTE) == "1.00 PB"

def test_format_size_negative():
    with pytest.raises(ValueError, match="Negative size not allowed"):
        format_size(-1024)
嘿哥们儿 2024-08-02 12:44:50

以下是使用 while 的选项:

def number_format(n):
   n2, n3 = n, 0
   while n2 >= 1e3:
      n2 /= 1e3
      n3 += 1
   return '%.3f' % n2 + ('', ' k', ' M', ' G')[n3]

s = number_format(9012345678)
print(s == '9.012 G')

https://docs. python.org/reference/compound_stmts.html#while

Here is an option using while:

def number_format(n):
   n2, n3 = n, 0
   while n2 >= 1e3:
      n2 /= 1e3
      n3 += 1
   return '%.3f' % n2 + ('', ' k', ' M', ' G')[n3]

s = number_format(9012345678)
print(s == '9.012 G')

https://docs.python.org/reference/compound_stmts.html#while

深爱成瘾 2024-08-02 12:44:50

使用。

from naturalsize import *
nsize(500)

从naturalsize 模块中

Use

from naturalsize import *
nsize(500)

from the naturalsize module.

何以笙箫默 2024-08-02 12:44:50

参考 Sridhar Ratnakumar 的回答,已更新至:

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)

示例输出为:

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

Referencing Sridhar Ratnakumar's answer, updated to:

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)

and example output is:

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
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文