Python format size application (converting B to KB, MB, GB, TB)

前端 未结 15 1656
轮回少年
轮回少年 2021-02-01 16:13

I am trying to write an application to convert bytes to kb to mb to gb to tb. Here\'s what I have so far:

def size_format(b):
    if b < 1000:
              r         


        
相关标签:
15条回答
  • 2021-02-01 16:30

    Yet another humanbytes version, with no loops/if..else, in python3 syntax.

    Test numbers stolen from @whereisalext's answer.

    Mind you, it's still a sketch, e.g. if the numbers are large enough it will traceback.

    import math as m
    
    
    MULTIPLES = ["B", "k{}B", "M{}B", "G{}B", "T{}B", "P{}B", "E{}B", "Z{}B", "Y{}B"]
    
    
    def humanbytes(i, binary=False, precision=2):
        base = 1024 if binary else 1000
        multiple = m.trunc(m.log2(i) / m.log2(base))
        value = i / m.pow(base, multiple)
        suffix = MULTIPLES[multiple].format("i" if binary else "")
        return f"{value:.{precision}f} {suffix}"
    
    
    if __name__ == "__main__":
        sizes = [
            1, 1024, 500000, 1048576, 50000000, 1073741824, 5000000000,
            1099511627776, 5000000000000]
    
        for i in sizes:
            print(f"{i} == {humanbytes(i)}, {humanbytes(i, binary=True)}")
    

    Results:

    1 == 1.00 B, 1.00 B
    1024 == 1.02 kB, 1.00 kiB
    500000 == 500.00 kB, 488.28 kiB
    1048576 == 1.05 MB, 1.00 MiB
    50000000 == 50.00 MB, 47.68 MiB
    1073741824 == 1.07 GB, 1.00 GiB
    5000000000 == 5.00 GB, 4.66 GiB
    1099511627776 == 1.10 TB, 1.00 TiB
    5000000000000 == 5.00 TB, 4.55 TiB
    

    Update:

    As pointed out in comments (and as noted originally: "Mind you, it's still a sketch"), this code is slow and buggy. Please see @mitch-mcmabers 's answer.

    Update 2: I was also lying about having no ifs.

    0 讨论(0)
  • 2021-02-01 16:32

    When you divide the value you're using an integer divide, since both values are integers. You need to convert one of them to float first:

    return '%.1f' % float(b)/1000 + 'KB'
    

    or even just

    return '%.1f' % b/1000.0 + 'KB'
    
    0 讨论(0)
  • 2021-02-01 16:36
    def humanbytes(B):
       'Return the given bytes as a human friendly KB, MB, GB, or TB string'
       B = float(B)
       KB = float(1024)
       MB = float(KB ** 2) # 1,048,576
       GB = float(KB ** 3) # 1,073,741,824
       TB = float(KB ** 4) # 1,099,511,627,776
    
       if B < KB:
          return '{0} {1}'.format(B,'Bytes' if 0 == B > 1 else 'Byte')
       elif KB <= B < MB:
          return '{0:.2f} KB'.format(B/KB)
       elif MB <= B < GB:
          return '{0:.2f} MB'.format(B/MB)
       elif GB <= B < TB:
          return '{0:.2f} GB'.format(B/GB)
       elif TB <= B:
          return '{0:.2f} TB'.format(B/TB)
    
    tests = [1, 1024, 500000, 1048576, 50000000, 1073741824, 5000000000, 1099511627776, 5000000000000]
    
    for t in tests: print '{0} == {1}'.format(t,humanbytes(t))
    

    Output:

    1 == 1.0 Byte
    1024 == 1.00 KB
    500000 == 488.28 KB
    1048576 == 1.00 MB
    50000000 == 47.68 MB
    1073741824 == 1.00 GB
    5000000000 == 4.66 GB
    1099511627776 == 1.00 TB
    5000000000000 == 4.55 TB
    

    and for future me here it is in Perl too:

    sub humanbytes {
       my $B = shift;
       my $KB = 1024;
       my $MB = $KB ** 2; # 1,048,576
       my $GB = $KB ** 3; # 1,073,741,824
       my $TB = $KB ** 4; # 1,099,511,627,776
    
       if ($B < $KB) {
          return "$B " . (($B == 0 || $B > 1) ? 'Bytes' : 'Byte');
       } elsif ($B >= $KB && $B < $MB) {
          return sprintf('%0.02f',$B/$KB) . ' KB';
       } elsif ($B >= $MB && $B < $GB) {
          return sprintf('%0.02f',$B/$MB) . ' MB';
       } elsif ($B >= $GB && $B < $TB) {
          return sprintf('%0.02f',$B/$GB) . ' GB';
       } elsif ($B >= $TB) {
          return sprintf('%0.02f',$B/$TB) . ' TB';
       }
    }
    
    0 讨论(0)
  • 2021-02-01 16:37

    This is a compact version that converts B (bytes) to any higher order such MB, GB without using a lot of if...else in python. I use bit-wise to deal with this. Also it allows to return a float output if you trigger the parameter return_output in the function as True:

    import math
    
    def bytes_conversion(number, return_float=False):
    
        def _conversion(number, return_float=False):
    
            length_number = int(math.log10(number))
    
            if return_float:
    
               length_number = int(math.log10(number))
               return length_number // 3, '%.2f' % (int(number)/(1 << (length_number//3) *10))
    
            return length_number // 3, int(number) >> (length_number//3) * 10
    
        unit_dict = {
            0: "B",  1: "kB",
            2: "MB", 3: "GB",
            4: "TB", 5: "PB",
            6: "EB"
        }
    
        if return_float:
    
            num_length, number = _conversion(number, return_float=return_float)
    
        else:
            num_length, number = _conversion(number)
    
        return "%s %s" % (number, unit_dict[num_length])
    
    #Example usage:
    #print(bytes_conversion(491266116, return_float=True))
    

    This is only a few of my posts in StackOverflow. Please let me know if I have any errors or violations.

    0 讨论(0)
  • 2021-02-01 16:37

    An output with no decimal places:

    >>> format_file_size(12345678)
    '11 MiB, 792 KiB, 334 bytes'
    
    format_file_size(
        def format_file_size(fsize):
            result = []
            units = {s: u for s, u in zip(reversed([2 ** n for n in range(0, 40, 10)]), ['GiB', 'MiB', 'KiB', 'bytes'])}
            for s, u in units.items():
                t = fsize // s
                if t > 0:
                    result.append('{} {}'.format(t, u))
                fsize = fsize % s
            return ', '.join(result) or '0 bytes'
    
    0 讨论(0)
  • 2021-02-01 16:37

    Fixed version of Bryan_Rch's answer:

    def format_bytes(size):
        # 2**10 = 1024
        power = 2**10
        n = 0
        power_labels = {0 : '', 1: 'kilo', 2: 'mega', 3: 'giga', 4: 'tera'}
        while size > power:
            size /= power
            n += 1
        return size, power_labels[n]+'bytes'
    
    0 讨论(0)
提交回复
热议问题