在Python中转换文件大小的更好方法
我使用的库读取文件并返回其大小(以字节为单位) 然后向最终用户显示该文件大小;为了让他们更容易理解,我通过将文件大小除以在Python中转换文件大小的更好方法,python,filesize,Python,Filesize,我使用的库读取文件并返回其大小(以字节为单位) 然后向最终用户显示该文件大小;为了让他们更容易理解,我通过将文件大小除以1024.0*1024.0来显式地将文件大小转换为MB。当然这是可行的,但我想知道有没有更好的方法在Python中实现这一点 我所说的更好,可能是指一个stdlib函数,它可以根据我想要的类型操作大小。就像我指定MB,它会自动将其除以1024.0*1024.0。在这些行上有一些标记。有一个标记,它将以字节为单位获取大小,并在需要时生成一个漂亮的字符串 >>>
1024.0*1024.0
来显式地将文件大小转换为MB
。当然这是可行的,但我想知道有没有更好的方法在Python中实现这一点
我所说的更好,可能是指一个stdlib函数,它可以根据我想要的类型操作大小。就像我指定MB
,它会自动将其除以1024.0*1024.0
。在这些行上有一些标记。有一个标记,它将以字节为单位获取大小,并在需要时生成一个漂亮的字符串
>>> from hurry.filesize import size
>>> size(11000)
'10K'
>>> size(198283722)
'189M'
或者,如果您想要1K==1000(这是大多数用户的假设):
它也有IEC支持(但没有记录):
因为它是由令人敬畏的Martijn Faassen编写的,所以代码小、清晰且可扩展。编写自己的系统非常容易
这里有一个:
mysystem = [
(1024 ** 5, ' Megamanys'),
(1024 ** 4, ' Lotses'),
(1024 ** 3, ' Tons'),
(1024 ** 2, ' Heaps'),
(1024 ** 1, ' Bunches'),
(1024 ** 0, ' Thingies'),
]
这样使用:
>>> from hurry.filesize import size
>>> size(11000, system=mysystem)
'10 Bunches'
>>> size(198283722, system=mysystem)
'189 Heaps'
您可以使用
而不是大小除数1024*1024
,以下是我使用的:
import math
def convert_size(size_bytes):
if size_bytes == 0:
return "0B"
size_name = ("B", "KB", "MB", "GB", "TB", "PB", "EB", "ZB", "YB")
i = int(math.floor(math.log(size_bytes, 1024)))
p = math.pow(1024, i)
s = round(size_bytes / p, 2)
return "%s %s" % (s, size_name[i])
注意:大小应以字节为单位发送。这里是计算大小的压缩函数
def GetHumanReadable(size,precision=2):
suffixes=['B','KB','MB','GB','TB']
suffixIndex = 0
while size > 1024 and suffixIndex < 4:
suffixIndex += 1 #increment the index of the suffix
size = size/1024.0 #apply the division
return "%.*f%s"%(precision,size,suffixes[suffixIndex])
def GetHumanReadable(大小、精度=2):
后缀=['B'、'KB'、'MB'、'GB'、'TB']
suffixIndex=0
当大小>1024且后缀索引<4时:
后缀索引+=1#增加后缀的索引
大小=大小/1024.0#应用除法
返回“%.*f%s”%(精度、大小、后缀[后缀索引])
有关更详细的输出以及反之亦然的操作,请参阅:以防有人搜索此问题的相反方向(正如我所做的),以下是对我有效的方法:
def get_bytes(size, suffix):
size = int(float(size))
suffix = suffix.lower()
if suffix == 'kb' or suffix == 'kib':
return size << 10
elif suffix == 'mb' or suffix == 'mib':
return size << 20
elif suffix == 'gb' or suffix == 'gib':
return size << 30
return False
def get_字节(大小、后缀):
大小=整数(浮动(大小))
后缀=后缀.lower()
如果后缀='kb'或后缀='kib':
返回大小这里是我的2美分,它允许上下铸造,并增加了可定制的精度:
def convertFloatToDecimal(f=0.0, precision=2):
'''
Convert a float to string of decimal.
precision: by default 2.
If no arg provided, return "0.00".
'''
return ("%." + str(precision) + "f") % f
def formatFileSize(size, sizeIn, sizeOut, precision=0):
'''
Convert file size to a string representing its value in B, KB, MB and GB.
The convention is based on sizeIn as original unit and sizeOut
as final unit.
'''
assert sizeIn.upper() in {"B", "KB", "MB", "GB"}, "sizeIn type error"
assert sizeOut.upper() in {"B", "KB", "MB", "GB"}, "sizeOut type error"
if sizeIn == "B":
if sizeOut == "KB":
return convertFloatToDecimal((size/1024.0), precision)
elif sizeOut == "MB":
return convertFloatToDecimal((size/1024.0**2), precision)
elif sizeOut == "GB":
return convertFloatToDecimal((size/1024.0**3), precision)
elif sizeIn == "KB":
if sizeOut == "B":
return convertFloatToDecimal((size*1024.0), precision)
elif sizeOut == "MB":
return convertFloatToDecimal((size/1024.0), precision)
elif sizeOut == "GB":
return convertFloatToDecimal((size/1024.0**2), precision)
elif sizeIn == "MB":
if sizeOut == "B":
return convertFloatToDecimal((size*1024.0**2), precision)
elif sizeOut == "KB":
return convertFloatToDecimal((size*1024.0), precision)
elif sizeOut == "GB":
return convertFloatToDecimal((size/1024.0), precision)
elif sizeIn == "GB":
if sizeOut == "B":
return convertFloatToDecimal((size*1024.0**3), precision)
elif sizeOut == "KB":
return convertFloatToDecimal((size*1024.0**2), precision)
elif sizeOut == "MB":
return convertFloatToDecimal((size*1024.0), precision)
添加TB
等,如您所愿。如果您已经知道所需的单位大小,这里有一些易于复制的单行线供您使用。如果你正在寻找一个更通用的功能,有一些不错的选择,请参阅我的2021年2月更新进一步
字节
千比特
print(“{:,.0f}.”格式(os.path.getsize(filepath)/float(1>>断言格式_字节(1024,“kB”)==“1 kB”
>>>断言格式_字节(7141000,“mb”)=“54 mb”
>>>断言格式_字节(7141000,“mib”)=“54 mib”
>>>断言格式_字节(7141000,“Mb”)=“54 Mb”
>>>断言格式_字节(7141000,“MB”)=“7 MB”
>>>断言格式_字节(7141000,“兆字节”)=“7兆字节”
>>>断言格式_字节(7141000,“gb”)=“0 gb”
>>>断言格式_字节(1000000,“kB”)=“977KB”
>>>断言格式\u字节(1000000,“kB”,SI=True)='1000 kB'
>>>断言格式_字节(1000000,“kb”)=“7812KB”
>>>断言格式_字节(1000000,“kb”,SI=True)='8000 kb'
>>>断言格式_字节(125000,“kb”)=“977KB”
>>>断言格式_字节(125000,“kb”,SI=True)='1000 kb'
>>>断言格式_字节(125*1024,“kb”)=“1000 kb”
>>>断言格式_字节(125*1024,“kb”,SI=True)='1024KB'
这是一个与ls-lh的输出相匹配的版本
def人类大小(num:int)->str:
基数=1
对于['B','K','M','G','T','P','E','Z','Y']中的单位:
n=数量/基数
如果n<9.95且单位为!=“B”:
#小于10,则保留小数点后1位
value=“{.1f}{}”。格式(n,单位)
返回值
如果圆形(n)<1000:
#少于4位,因此请使用此选项
value=“{}{}”。格式(四舍五入,单位)
返回值
基数*=1024
value=“{}{}”。格式(四舍五入,单位)
返回值
以下是我的实现:
from bisect import bisect
def to_filesize(bytes_num, si=True):
decade = 1000 if si else 1024
partitions = tuple(decade ** n for n in range(1, 6))
suffixes = tuple('BKMGTP')
i = bisect(partitions, bytes_num)
s = suffixes[i]
for n in range(i):
bytes_num /= decade
f = '{:.3f}'.format(bytes_num)
return '{}{}'.format(f.rstrip('0').rstrip('.'), s)
它最多可以打印三个小数,并去除尾随的零和句点。布尔参数si
将切换基于10和基于2的大小大小大小
这是它的对应项。它允许编写干净的配置文件,如{'maximum\u filesize':from\u filesize('10M')
。它返回一个近似于预期文件大小的整数。我不使用位移位,因为源值是一个浮点数(它将接受from\u filesize('2.15M')
)。将其转换为整数/十进制可能会起作用,但会使代码更加复杂,而且它已经按原样工作了
def from_filesize(spec, si=True):
decade = 1000 if si else 1024
suffixes = tuple('BKMGTP')
num = float(spec[:-1])
s = spec[-1]
i = suffixes.index(s)
for n in range(i):
num *= decade
return int(num)
这是:
def convert_字节(大小):
对于x,单位为[‘字节’、‘KB’、‘MB’、‘GB’、‘TB’]:
如果尺寸小于1024.0:
返回“%3.1f%s%”(大小,x)
大小/=1024.0
返回大小
输出
>>转换字节(1024)
“1.0 KB”
>>>转换_字节(102400)
“100.0 KB”
单位={1000:['KB','MB','GB'],
1024:['KiB','MiB','GiB']}
def近似_大小(大小、标志_1024_或_1000=真):
如果标志为1024或1000,则mult=1024,否则为1000
对于单位中的单位[mult]:
大小=大小/倍数
如果尺寸
我想要双向转换,我想使用Python 3 format()支持来实现最具Python风格的转换。也许可以尝试使用datasize库模块
所以写一个。还要注意,现在许多系统使用MB表示10^6,而不是2^20。@A,@tc:请记住,SI和IEC的标准是kB(千字节)表示1.000字节
,而KiB(千字节)表示1.024字节
。请看。@Bobby:kB实际上是“千字节”的意思,等于10000 dB。字节没有SI单位。IIRC,IEC建议KiB,但不定义kB或kB。@tc。前缀kilo由SI定义为1000。IEC定义kB等,以使用SI前缀而不是2^10。我的意思是前缀通常由SI定义,但数据大小的缩写不是:。这些由IEC定义:如果y您正在以字节为单位发送大小,然后只需将“B”添加为大小\名称的第一个元素。当文件大小为0字节时,它将失败。未定义日志(0,1024)!您应该检查0
print ('{:,.0f}'.format(os.path.getsize(filepath))+" B")
print ('{:,.0f}'.format(os.path.getsize(filepath)/float(1<<7))+" kb")
print ('{:,.0f}'.format(os.path.getsize(filepath)/float(1<<10))+" KB")
print ('{:,.0f}'.format(os.path.getsize(filepath)/float(1<<17))+" mb")
print ('{:,.0f}'.format(os.path.getsize(filepath)/float(1<<20))+" MB")
print ('{:,.0f}'.format(os.path.getsize(filepath)/float(1<<27))+" gb")
print ('{:,.0f}'.format(os.path.getsize(filepath)/float(1<<30))+" GB")
print ('{:,.0f}'.format(os.path.getsize(filepath)/float(1<<40))+" TB")
from pathlib import Path
def get_path_size(path = Path('.'), recursive=False):
"""
Gets file size, or total directory size
Parameters
----------
path: str | pathlib.Path
File path or directory/folder path
recursive: bool
True -> use .rglob i.e. include nested files and directories
False -> use .glob i.e. only process current directory/folder
Returns
-------
int:
File size or recursive directory size in bytes
Use cleverutils.format_bytes to convert to other units e.g. MB
"""
path = Path(path)
if path.is_file():
size = path.stat().st_size
elif path.is_dir():
path_glob = path.rglob('*.*') if recursive else path.glob('*.*')
size = sum(file.stat().st_size for file in path_glob)
return size
def format_bytes(bytes, unit, SI=False):
"""
Converts bytes to common units such as kb, kib, KB, mb, mib, MB
Parameters
---------
bytes: int
Number of bytes to be converted
unit: str
Desired unit of measure for output
SI: bool
True -> Use SI standard e.g. KB = 1000 bytes
False -> Use JEDEC standard e.g. KB = 1024 bytes
Returns
-------
str:
E.g. "7 MiB" where MiB is the original unit abbreviation supplied
"""
if unit.lower() in "b bit bits".split():
return f"{bytes*8} {unit}"
unitN = unit[0].upper()+unit[1:].replace("s","") # Normalised
reference = {"Kb Kib Kibibit Kilobit": (7, 1),
"KB KiB Kibibyte Kilobyte": (10, 1),
"Mb Mib Mebibit Megabit": (17, 2),
"MB MiB Mebibyte Megabyte": (20, 2),
"Gb Gib Gibibit Gigabit": (27, 3),
"GB GiB Gibibyte Gigabyte": (30, 3),
"Tb Tib Tebibit Terabit": (37, 4),
"TB TiB Tebibyte Terabyte": (40, 4),
"Pb Pib Pebibit Petabit": (47, 5),
"PB PiB Pebibyte Petabyte": (50, 5),
"Eb Eib Exbibit Exabit": (57, 6),
"EB EiB Exbibyte Exabyte": (60, 6),
"Zb Zib Zebibit Zettabit": (67, 7),
"ZB ZiB Zebibyte Zettabyte": (70, 7),
"Yb Yib Yobibit Yottabit": (77, 8),
"YB YiB Yobibyte Yottabyte": (80, 8),
}
key_list = '\n'.join([" b Bit"] + [x for x in reference.keys()]) +"\n"
if unitN not in key_list:
raise IndexError(f"\n\nConversion unit must be one of:\n\n{key_list}")
units, divisors = [(k,v) for k,v in reference.items() if unitN in k][0]
if SI:
divisor = 1000**divisors[1]/8 if "bit" in units else 1000**divisors[1]
else:
divisor = float(1 << divisors[0])
value = bytes / divisor
if value != 1 and len(unitN) > 3:
unitN += "s" # Create plural unit of measure
return "{:,.0f}".format(value) + " " + unitN
# Tests
>>> assert format_bytes(1,"b") == '8 b'
>>> assert format_bytes(1,"bits") == '8 bits'
>>> assert format_bytes(1024, "kilobyte") == "1 Kilobyte"
>>> assert format_bytes(1024, "kB") == "1 KB"
>>> assert format_bytes(7141000, "mb") == '54 Mb'
>>> assert format_bytes(7141000, "mib") == '54 Mib'
>>> assert format_bytes(7141000, "Mb") == '54 Mb'
>>> assert format_bytes(7141000, "MB") == '7 MB'
>>> assert format_bytes(7141000, "mebibytes") == '7 Mebibytes'
>>> assert format_bytes(7141000, "gb") == '0 Gb'
>>> assert format_bytes(1000000, "kB") == '977 KB'
>>> assert format_bytes(1000000, "kB", SI=True) == '1,000 KB'
>>> assert format_bytes(1000000, "kb") == '7,812 Kb'
>>> assert format_bytes(1000000, "kb", SI=True) == '8,000 Kb'
>>> assert format_bytes(125000, "kb") == '977 Kb'
>>> assert format_bytes(125000, "kb", SI=True) == '1,000 Kb'
>>> assert format_bytes(125*1024, "kb") == '1,000 Kb'
>>> assert format_bytes(125*1024, "kb", SI=True) == '1,024 Kb'
def human_size(num: int) -> str:
base = 1
for unit in ['B', 'K', 'M', 'G', 'T', 'P', 'E', 'Z', 'Y']:
n = num / base
if n < 9.95 and unit != 'B':
# Less than 10 then keep 1 decimal place
value = "{:.1f}{}".format(n, unit)
return value
if round(n) < 1000:
# Less than 4 digits so use this
value = "{}{}".format(round(n), unit)
return value
base *= 1024
value = "{}{}".format(round(n), unit)
return value
from bisect import bisect
def to_filesize(bytes_num, si=True):
decade = 1000 if si else 1024
partitions = tuple(decade ** n for n in range(1, 6))
suffixes = tuple('BKMGTP')
i = bisect(partitions, bytes_num)
s = suffixes[i]
for n in range(i):
bytes_num /= decade
f = '{:.3f}'.format(bytes_num)
return '{}{}'.format(f.rstrip('0').rstrip('.'), s)
def from_filesize(spec, si=True):
decade = 1000 if si else 1024
suffixes = tuple('BKMGTP')
num = float(spec[:-1])
s = spec[-1]
i = suffixes.index(s)
for n in range(i):
num *= decade
return int(num)
UNITS = {1000: ['KB', 'MB', 'GB'],
1024: ['KiB', 'MiB', 'GiB']}
def approximate_size(size, flag_1024_or_1000=True):
mult = 1024 if flag_1024_or_1000 else 1000
for unit in UNITS[mult]:
size = size / mult
if size < mult:
return '{0:.3f} {1}'.format(size, unit)
approximate_size(2123, False)
$ pip install -qqq datasize
$ python
...
>>> from datasize import DataSize
>>> 'My new {:GB} SSD really only stores {:.2GiB} of data.'.format(DataSize('750GB'),DataSize(DataSize('750GB') * 0.8))
'My new 750GB SSD really only stores 558.79GiB of data.'