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
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 if
s.
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'
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';
}
}
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.
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'
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'