如何在C ++中打印出人类可读的文件大小而没有循环

问题描述

我想用C ++打印文件大小。我的输入以字节为单位,如果超过KiB,我想在1024中打印;如果超过MiB,我要在1024*1024中打印,等等。 KB代表1000及更高版本,依此类推。

它也应该有一个小数部分,以便我可以区分1.5 GiB1.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);

解决方法

对数底数10001024确实可以用于确定正确的单位。实际上,我们只需要对数的整数部分,所以该部分位于小数点前面。在现代硬件上,可以在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;
}

相关问答

错误1:Request method ‘DELETE‘ not supported 错误还原:...
错误1:启动docker镜像时报错:Error response from daemon:...
错误1:private field ‘xxx‘ is never assigned 按Alt...
报错如下,通过源不能下载,最后警告pip需升级版本 Requirem...