如何解决如何在C ++中打印出人类可读的文件大小而没有循环
我想用C ++打印文件大小。我的输入以字节为单位,如果超过KiB
,我想在1024
中打印;如果超过MiB
,我要在1024*1024
中打印,等等。 KB
代表1000
及更高版本,依此类推。
它也应该有一个小数部分,以便我可以区分1.5 GiB
和1.2 GiB
。
我所知道的是,我可以使用对数来计算选择哪个单位。因此,如果log_1024(x) >= 1
应该在KiB
中。这样我可以避免不必要的循环。
另外,I have a function for printing the fractions already:
std::string stringifyFraction(unsigned numerator,unsigned denominator,unsigned precision);
解决方法
对数底数1000
或1024
确实可以用于确定正确的单位。实际上,我们只需要对数的整数部分,所以该部分位于小数点前面。在现代硬件上,可以在O(1)
中计算整数对数,因此这比使用for
循环获得正确的单位要快一些。 Here you can find out how to efficiently compute the integer logarithm of a number。
如果整数部分为0
,则在B
中打印,在1
中以KiB
打印,依此类推。我们可以创建一个查找表,其中的键是对数:
constexpr const char FILE_SIZE_UNITS[8][3]{
"B","KB","MB","GB","TB","PB","EB","ZB"
};
请注意,该表使用3
作为内部大小,因为所有字符串都以空字符结尾。
您可能还想知道为什么查找表中不包含KiB
单位。这是因为中间的i
是常量,不需要成为表的一部分。此外,文件大小有两种不同的单位制,一种是基本1000
,另一种是基本1024
。参见Files size units: “KiB” vs “KB” vs “kB”。我们可以轻松地在一个功能中同时支持这两种功能。
然后我们可以按以下方式实现我们的stringifyFileSize
方法:
// use SFINAE to only allow base 1000 or 1024
template <size_t BASE = 1024,std::enable_if_t<BASE == 1000 || BASE == 1024,int> = 0>
std::string stringifyFileSize(uint64_t size,unsigned precision = 0) noexcept
{
constexpr const char FILE_SIZE_UNITS[8][3]{
"B","ZB"
};
// The linked post about computing the integer logarithm
// explains how to compute this.
// This is equivalent to making a table: {1,1000,1000 * 1000,...}
// or {1,1024,1024 * 1024,...}
constexpr auto powers = makePowerTable<Uint,BASE>();
unsigned unit = logFloor<BASE>(size);
// Your numerator is size,your denominator is 1000^unit or 1024^unit.
std::string result = stringifyFraction(size,powers[unit],precision);
result.reserve(result.size() + 5);
// Optional: Space separating number from unit. (usually looks better)
result.push_back(' ');
char first = FILE_SIZE_UNITS[unit][0];
// Optional: Use lower case (kB,mB,etc.) for decimal units
if constexpr (BASE == 1000) {
first += 'a' - 'A';
}
result.push_back(first);
// Don't insert anything more in case of single bytes.
if (unit != 0) {
if constexpr (BASE == 1024) {
result.push_back('i');
}
result.push_back(FILE_SIZE_UNITS[unit][1]);
}
return result;
}
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。