我想将单个字节数转换为文件大小(具有.KB,.MB和.GB)。

如果数字为0,则我不需要任何单位。
如果数字可以精确地整除1024的倍数(不是浮点数),那么我将打印:x。否则,我想以1度精度打印浮点。

我编写了一些看起来运行良好的代码,但这非常麻烦。我正在研究可以使功能更清洁/更高效的方法,说实话,这非常丑陋:

char *
calculateSize( off_t size )
{
  char *result = (char *) malloc(sizeof(char) * 20);
  static int GB = 1024 * 1024 * 1024;
  static int MB = 1024 * 1024;
  static int KB = 1024;
  if (size >= GB) {
    if (size % GB == 0)
      sprintf(result, "%d GB", size / GB);
    else
      sprintf(result, "%.1f GB", (float) size / GB);
  }
  else if (size >= MB) {
    if (size % MB == 0)
      sprintf(result, "%d MB", size / MB);
    else
      sprintf(result, "%.1f MB", (float) size / MB);
  }
  else {
    if (size == 0) {
      result[0] = '0';
      result[1] = '\0';
    }
    else {
      if (size % KB == 0)
        sprintf(result, "%d KB", size / KB);
      else
        sprintf(result, "%.1f KB", (float) size / KB);
    }
  }
  return result;
}

如果有人可以用更好的方法达到相同的效果,我将不胜感激。

最佳答案

使用表驱动的表示形式可以扩展到EiB。

#include <inttypes.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#define DIM(x) (sizeof(x)/sizeof(*(x)))

static const char     *sizes[]   = { "EiB", "PiB", "TiB", "GiB", "MiB", "KiB", "B" };
static const uint64_t  exbibytes = 1024ULL * 1024ULL * 1024ULL *
                                   1024ULL * 1024ULL * 1024ULL;

char *
calculateSize(uint64_t size)
{
    char     *result = (char *) malloc(sizeof(char) * 20);
    uint64_t  multiplier = exbibytes;
    int i;

    for (i = 0; i < DIM(sizes); i++, multiplier /= 1024)
    {
        if (size < multiplier)
            continue;
        if (size % multiplier == 0)
            sprintf(result, "%" PRIu64 " %s", size / multiplier, sizes[i]);
        else
            sprintf(result, "%.1f %s", (float) size / multiplier, sizes[i]);
        return result;
    }
    strcpy(result, "0");
    return result;
}

测试码
int main(void)
{
    uint64_t list[] =
    {
        0, 1, 2, 34, 900, 1023, 1024, 1025, 2048, 1024 * 1024,
        1024 * 1024 * 1024 + 1024 * 1024 * 400
    };
    int i;
    for (i = 0; i < DIM(list); i++)
    {
        char *str = calculateSize(list[i]);
        printf("%18" PRIu64 " = %s\n", list[i], str);
        free(str);
    }
    return 0;
}

测试输出
                 0 = 0
                 1 = 1 B
                 2 = 2 B
                34 = 34 B
               900 = 900 B
              1023 = 1023 B
              1024 = 1 KiB
              1025 = 1.0 KiB
              2048 = 2 KiB
           1048576 = 1 MiB
        1493172224 = 1.4 GiB

10-07 20:39