我使用这个函数将文件大小(以字节为单位)转换为人类可读的文件大小:

零二线函数 var i = -1; var byteUnits =[英国‘计划生育’‘兆’,‘和合’,‘PB’‘EB”、“ZB’,‘YB]; do { fileSizeInBytes /= 1024; 我+; while (fileSizeInBytes > 1024) 数学归来。max(fileSizeInBytes, 0.1)。toFixed(1) + byteUnits[i]; 的 控制台日志(getReadableFileSizeString (1551859712);//输出是“1.4 GB”

然而,这似乎不是百分之百准确的。例如:

getReadableFileSizeString(1551859712); // output is "1.4 GB"

不应该是“1.5 GB”吗?除以1024似乎失去了精度。是我完全误解了什么,还是有更好的办法?


当前回答

我写了一个大小转换函数,它也接受人类可读的格式。

JS

const bitBase = 8; const suffixes = { bit: 'b', b: 'B', kb: 'KB', mb: 'MB', gb: 'GB', tb: 'TB', }; const multipliers = { bit: { toBitHr: 1, toB: 1 / bitBase, toKB: 1 / (bitBase * 1e3), toMB: 1 / (bitBase * 1e6), toGB: 1 / (bitBase * 1e9), toTB: 1 / (bitBase * 1e12), }, B: { toBit: bitBase, toBHr: 1, toKB: 1 / 1e3, toMB: 1 / 1e6, toGB: 1 / 1e9, toTB: 1 / 1e12, }, KB: { toBit: 1 / (bitBase * 1e3), toB: 1e3, toKBHr: 1, toMB: 1 / 1e3, toGB: 1 / 1e6, toTB: 1 / 1e9, }, MB: { toBit: bitBase * 1e6, toB: 1e6, toKB: 1e3, toMBHr: 1, toGB: 1 / 1e3, toTB: 1 / 1e6, }, GB: { toBit: bitBase * 1e9, toB: 1e9, toKB: 1e6, toMB: 1e3, toGBHr: 1, toTB: 1 / 1e3, }, TB: { toBit: bitBase * 1e12, toB: 1e12, toKB: 1e9, toMB: 1e6, toGB: 1e3, toTBHr: 1, }, }; const round = (num, decimalPlaces) => { const strNum = num.toString(); const isExp = strNum.includes('e'); if (isExp) { return Number(num.toPrecision(decimalPlaces + 1)); } return Number( `${Math.round(Number(`${num}e${decimalPlaces}`))}e${decimalPlaces * -1}`, ); }; function conv( value, hr, rnd, multiplier, suffix, ) { let val = value * multiplier; if ((value * multiplier) > Number.MAX_SAFE_INTEGER) { val = Number.MAX_SAFE_INTEGER; } if (val < Number.MIN_VALUE) val = 0; if ((rnd || rnd === 0) && val < Number.MAX_SAFE_INTEGER) { val = round(val, rnd); } if (hr) return `${val}${suffix}`; return val; } const MemConv = (function _() { return { bit(value) { return { toBitHr(opts = {}) { return conv( value, true, opts.round || false, multipliers.bit.toBitHr, suffixes.bit, ); }, toB(opts = {}) { return conv( value, opts.hr || false, opts.round || false, multipliers.bit.toB, suffixes.b, ); }, toKB(opts = {}) { return conv( value, opts.hr || false, opts.round || false, multipliers.bit.toKB, suffixes.kb, ); }, toMB(opts = {}) { return conv( value, opts.hr || false, opts.round || false, multipliers.bit.toMB, suffixes.mb, ); }, toGB(opts = {}) { return conv( value, opts.hr || false, opts.round || false, multipliers.bit.toGB, suffixes.gb, ); }, toTB(opts = {}) { return conv( value, opts.hr || false, opts.round || false, multipliers.bit.toTB, suffixes.tb, ); }, }; }, B(value) { return { toBit(opts = {}) { return conv( value, opts.hr || false, opts.round || false, multipliers.B.toBit, suffixes.bit, ); }, toBHr(opts = {}) { return conv( value, true, opts.round || false, multipliers.B.toBHr, suffixes.b, ); }, toKB(opts = {}) { return conv( value, opts.hr || false, opts.round || false, multipliers.B.toKB, suffixes.kb, ); }, toMB(opts = {}) { return conv( value, opts.hr || false, opts.round || false, multipliers.B.toMB, suffixes.mb, ); }, toGB(opts = {}) { return conv( value, opts.hr || false, opts.round || false, multipliers.B.toGB, suffixes.gb, ); }, toTB(opts = {}) { return conv( value, opts.hr || false, opts.round || false, multipliers.B.toTB, suffixes.tb, ); }, }; }, KB(value) { return { toBit(opts = {}) { return conv( value, opts.hr || false, opts.round || false, multipliers.KB.toBit, suffixes.bit, ); }, toB(opts = {}) { return conv( value, opts.hr || false, opts.round || false, multipliers.KB.toB, suffixes.b, ); }, toKBHr(opts = {}) { return conv( value, true, opts.round || false, multipliers.KB.toKBHr, suffixes.kb, ); }, toMB(opts = {}) { return conv( value, opts.hr || false, opts.round || false, multipliers.KB.toMB, suffixes.mb, ); }, toGB(opts = {}) { return conv( value, opts.hr || false, opts.round || false, multipliers.KB.toGB, suffixes.gb, ); }, toTB(opts = {}) { return conv( value, opts.hr || false, opts.round || false, multipliers.KB.toTB, suffixes.tb, ); }, }; }, MB(value) { return { toBit(opts = {}) { return conv( value, opts.hr || false, opts.round || false, multipliers.MB.toBit, suffixes.bit, ); }, toB(opts = {}) { return conv( value, opts.hr || false, opts.round || false, multipliers.MB.toB, suffixes.b, ); }, toKB(opts = {}) { return conv( value, opts.hr || false, opts.round || false, multipliers.MB.toKB, suffixes.kb, ); }, toMBHr(opts = {}) { return conv( value, true, opts.round || false, multipliers.MB.toMBHr, suffixes.mb, ); }, toGB(opts = {}) { return conv( value, opts.hr || false, opts.round || false, multipliers.MB.toGB, suffixes.gb, ); }, toTB(opts = {}) { return conv( value, opts.hr || false, opts.round || false, multipliers.MB.toTB, suffixes.tb, ); }, }; }, GB(value) { return { toBit(opts = {}) { return conv( value, opts.hr || false, opts.round || false, multipliers.GB.toBit, suffixes.bit, ); }, toB(opts = {}) { return conv( value, opts.hr || false, opts.round || false, multipliers.GB.toB, suffixes.b, ); }, toKB(opts = {}) { return conv( value, opts.hr || false, opts.round || false, multipliers.GB.toKB, suffixes.kb, ); }, toMB(opts = {}) { return conv( value, opts.hr || false, opts.round || false, multipliers.GB.toMB, suffixes.mb, ); }, toGBHr(opts = {}) { return conv( value, true, opts.round || false, multipliers.GB.toGBHr, suffixes.gb, ); }, toTB(opts = {}) { return conv( value, opts.hr || false, opts.round || false, multipliers.GB.toTB, suffixes.tb, ); }, }; }, TB(value) { return { toBit(opts = {}) { return conv( value, opts.hr || false, opts.round || false, multipliers.TB.toBit, suffixes.bit, ); }, toB(opts = {}) { return conv( value, opts.hr || false, opts.round || false, multipliers.TB.toB, suffixes.b, ); }, toKB(opts = {}) { return conv( value, opts.hr || false, opts.round || false, multipliers.TB.toKB, suffixes.kb, ); }, toMB(opts = {}) { return conv( value, opts.hr || false, opts.round || false, multipliers.TB.toMB, suffixes.mb, ); }, toGB(opts = {}) { return conv( value, opts.hr || false, opts.round || false, multipliers.TB.toGB, suffixes.gb, ); }, toTBHr(opts = {}) { return conv( value, true, opts.round || false, multipliers.TB.toTBHr, suffixes.tb, ); }, }; }, }; }()); const testCases = [1, 10, 150, 1000, 74839.67346]; const HRSuffixes = Object.values(suffixes); const roundDecimals = 2; const precision = Number(`0.${'0'.repeat(roundDecimals)}5`); const SCIENTIFIC_NOT_NUMBER_REGXP = /[-+]?[0-9]*.?[0-9]+([eE][-+]?[0-9]+)?/g; const SUFFIX_REGXP = /[a-z]+$/i; const CONVERSION_TO_REGXP = /(?<=to).*(?=hr+$)|(?<=to).*(?=hr+$)?/i; for (const conversionFrom of (Object.keys(MemConv))) { for (const tCase of testCases) { const convFunc = MemConv[conversionFrom](tCase); for (const [conversionToFn, f] of Object.entries(convFunc)) { const conversionTo = (conversionToFn.match(CONVERSION_TO_REGXP) || [conversionToFn])[0]; const result = f(); const humanReadable = f({ hr: true }); const rounded = f({ round: roundDecimals }); const roundedAndHumanReadable = f({ hr: true, round: roundDecimals }); console.log({ value: tCase, from: conversionFrom, to: conversionTo, result, humanReadable, rounded, roundedAndHumanReadable, }); } } }

TSVersion

test

import assert from 'assert';

function test() {
  const testCases = [1, 10, 150, 1000, 74839.67346];
  const HRSuffixes = Object.values(suffixes);
  const roundDecimals = 2;
  const precision = Number(`0.${'0'.repeat(roundDecimals)}5`);
  const SCIENTIFIC_NOT_NUMBER_REGXP = /[-+]?[0-9]*.?[0-9]+([eE][-+]?[0-9]+)?/g;
  const SUFFIX_REGXP = /[a-z]+$/i;
  const CONVERSION_TO_REGXP = /(?<=to).*(?=hr+$)|(?<=to).*(?=hr+$)?/i;

  for (const conversionFrom of (Object.keys(MemConv) as (keyof typeof MemConv)[])) {
    for (const tCase of testCases) {
      const convFunc = MemConv[conversionFrom](tCase);
      for (const [conversionToFn, f] of Object.entries(convFunc)) {
        const conversionTo = (conversionToFn.match(CONVERSION_TO_REGXP) || [conversionToFn])[0];
        const expectedSuffix = suffixes[conversionTo.toLowerCase() as keyof typeof suffixes];
        const multiplier = multipliers[conversionFrom][conversionToFn as keyof typeof multipliers[typeof conversionFrom]];
        const expectedResult = tCase * multiplier > Number.MAX_SAFE_INTEGER
            ? Number.MAX_SAFE_INTEGER
            : tCase * multiplier;

        const result = f();
        const humanReadable = f({ hr: true });
        const rounded = f({ round: roundDecimals });
        const roundedAndHumanReadable = f({ hr: true, round: roundDecimals });

        const resHrNumber = Number((humanReadable.match(SCIENTIFIC_NOT_NUMBER_REGXP) || [''])[0]);
        const resHrSuffix = (humanReadable.match(SUFFIX_REGXP) || [0])[0];
        const resRoundHrNumber = Number((roundedAndHumanReadable.match(SCIENTIFIC_NOT_NUMBER_REGXP) || [''])[0]);
        const resRoundHrSuffix = (roundedAndHumanReadable.match(SUFFIX_REGXP) || [0])[0];

        if (/hr$/i.test(conversionToFn)) {
          const resNumber = Number((humanReadable.match(SCIENTIFIC_NOT_NUMBER_REGXP) || [''])[0]);
          const resSuffix = (humanReadable.match(SUFFIX_REGXP) || [0])[0];
          assert(typeof result === 'string');
          assert(typeof resSuffix === 'string');
          assert(typeof resRoundHrNumber === 'number');
          assert(typeof rounded === 'string');
          assert(result === humanReadable);
          assert(resSuffix === expectedSuffix);
          assert(resNumber <= expectedResult + precision && resNumber >= expectedResult - precision);
        } else {
          assert(typeof result === 'number');
          assert(result === resHrNumber);
          assert(typeof rounded === 'number');
          assert(result <= expectedResult + precision && result >= expectedResult - precision);
        }

        console.log({
          value: tCase,
          from: conversionFrom,
          to: conversionToFn,
          result,
          humanReadable,
          rounded,
          roundedAndHumanReadable,
        });

        assert(typeof resHrSuffix === 'string');
        assert(typeof resHrNumber === 'number');
        assert(resHrSuffix === expectedSuffix);
        assert(resHrSuffix === resRoundHrSuffix);
        assert(HRSuffixes.includes(resHrSuffix));
      }
    }
  }
}
test();

使用

// GB to GB humanReadable
console.log(MemConv.GB(11.1942).toGBHr()); // 11.1942GB;
// GB to MB
console.log(MemConv.GB(11.1942).toMB());// 11194.2;
// MB to MB humanReadable
console.log(MemConv.MB(11.1942).toGB({ hr: true }));// 0.011194200000000001GB;
// MB to MB humanReadable with rounding
console.log(MemConv.MB(11.1942).toGB({ hr: true, round: 3 }));// 0.011GB;

其他回答

Let bytes = 1024 * 10 * 10 * 10;

控制台日志(getReadableFileSizeString(字节)。

将返回1000.0Кб而不是1MB

下面是另一个国际化的实现,用TypeScript编写:

const UNITS = ['byte', 'kilobyte', 'megabyte', 'gigabyte', 'terabyte', 'petabyte']
const BYTES_PER_KB = 1000


/**
 * Format bytes as human-readable text.
 *
 * @param sizeBytes Number of bytes.
 *
 * @return Formatted string.
 */
export function humanFileSize(sizeBytes: number | bigint): string {
    let size = Math.abs(Number(sizeBytes))

    let u = 0
    while(size >= BYTES_PER_KB && u < UNITS.length-1) {
        size /= BYTES_PER_KB
        ++u
    }

    return new Intl.NumberFormat([], {
        style: 'unit',
        unit: UNITS[u],
        unitDisplay: 'short',
        maximumFractionDigits: 1,
    }).format(size)
}

将[]替换为像fr这样的语言代码,以强制进行默认以外的本地化。

console.log(humanFileSize(0))
console.log(humanFileSize(9))
console.log(humanFileSize(99))
console.log(humanFileSize(999))
console.log(humanFileSize(1000))
console.log(humanFileSize(1001))
console.log(humanFileSize(1023))
console.log(humanFileSize(1024))
console.log(humanFileSize(1025))
console.log(humanFileSize(100_000))
console.log(humanFileSize(1_000_000))
console.log(humanFileSize(1_000_000_000))
console.log(humanFileSize(1_000_000_000_000))
console.log(humanFileSize(1_000_000_000_000_000))
console.log(humanFileSize(1_000_000_000_000_000_000))
// fr
0 o
9 o
99 o
999 o
1 ko
1 ko
1 ko
1 ko
1 ko
100 ko
1 Mo
1 Go
1 To
1 Po
1 000 Po

// en-US
0 byte
9 byte
99 byte
999 byte
1 kB
1 kB
1 kB
1 kB
1 kB
100 kB
1 MB
1 GB
1 TB
1 PB
1,000 PB

你可以得到国际。NumberFormat为您自动进行单位转换。如。

const sizeFormatter = new Intl.NumberFormat([], { style: 'unit', unit: 'byte', notation: "compact", unitDisplay: "narrow", }) console.log(sizeFormatter.format(0)) console.log(sizeFormatter.format(1)) console.log(sizeFormatter.format(999)) console.log(sizeFormatter.format(1000)) console.log(sizeFormatter.format(1023)) console.log(sizeFormatter.format(1024)) console.log(sizeFormatter.format(1024**2)) console.log(sizeFormatter.format(1024**3)) console.log(sizeFormatter.format(1024**4)) console.log(sizeFormatter.format(1024**5)) console.log(sizeFormatter.format(1024**6))

...但是单位有点奇怪。例如1024**4是1.1BB,我猜是“十亿字节”;我不认为有人会用它,即使它在技术上是正确的。

基于cocco的答案,但略有淡化(老实说,那些我觉得舒服的被保留/添加),不显示后面的0,但仍然支持0,希望对其他人有用:

函数fileSizeSI(size) { var e = (Math.log(size) / Math.log(1e3)) | 0; return +(size / Math.)战俘(1 e3, e)) .toFixed (2 ) + ' ' + (' kMGTPEZY [e - 1 ] || '') + ' B”; } / /测试: 文档。write([0, 23, 4322, 324232132, 22e9, 64.22e12, 76.22e15, 64.66e18, 77.11e21, 22e24].map(fileSizeSI).join('<br>'));

我写了一个大小转换函数,它也接受人类可读的格式。

JS

const bitBase = 8; const suffixes = { bit: 'b', b: 'B', kb: 'KB', mb: 'MB', gb: 'GB', tb: 'TB', }; const multipliers = { bit: { toBitHr: 1, toB: 1 / bitBase, toKB: 1 / (bitBase * 1e3), toMB: 1 / (bitBase * 1e6), toGB: 1 / (bitBase * 1e9), toTB: 1 / (bitBase * 1e12), }, B: { toBit: bitBase, toBHr: 1, toKB: 1 / 1e3, toMB: 1 / 1e6, toGB: 1 / 1e9, toTB: 1 / 1e12, }, KB: { toBit: 1 / (bitBase * 1e3), toB: 1e3, toKBHr: 1, toMB: 1 / 1e3, toGB: 1 / 1e6, toTB: 1 / 1e9, }, MB: { toBit: bitBase * 1e6, toB: 1e6, toKB: 1e3, toMBHr: 1, toGB: 1 / 1e3, toTB: 1 / 1e6, }, GB: { toBit: bitBase * 1e9, toB: 1e9, toKB: 1e6, toMB: 1e3, toGBHr: 1, toTB: 1 / 1e3, }, TB: { toBit: bitBase * 1e12, toB: 1e12, toKB: 1e9, toMB: 1e6, toGB: 1e3, toTBHr: 1, }, }; const round = (num, decimalPlaces) => { const strNum = num.toString(); const isExp = strNum.includes('e'); if (isExp) { return Number(num.toPrecision(decimalPlaces + 1)); } return Number( `${Math.round(Number(`${num}e${decimalPlaces}`))}e${decimalPlaces * -1}`, ); }; function conv( value, hr, rnd, multiplier, suffix, ) { let val = value * multiplier; if ((value * multiplier) > Number.MAX_SAFE_INTEGER) { val = Number.MAX_SAFE_INTEGER; } if (val < Number.MIN_VALUE) val = 0; if ((rnd || rnd === 0) && val < Number.MAX_SAFE_INTEGER) { val = round(val, rnd); } if (hr) return `${val}${suffix}`; return val; } const MemConv = (function _() { return { bit(value) { return { toBitHr(opts = {}) { return conv( value, true, opts.round || false, multipliers.bit.toBitHr, suffixes.bit, ); }, toB(opts = {}) { return conv( value, opts.hr || false, opts.round || false, multipliers.bit.toB, suffixes.b, ); }, toKB(opts = {}) { return conv( value, opts.hr || false, opts.round || false, multipliers.bit.toKB, suffixes.kb, ); }, toMB(opts = {}) { return conv( value, opts.hr || false, opts.round || false, multipliers.bit.toMB, suffixes.mb, ); }, toGB(opts = {}) { return conv( value, opts.hr || false, opts.round || false, multipliers.bit.toGB, suffixes.gb, ); }, toTB(opts = {}) { return conv( value, opts.hr || false, opts.round || false, multipliers.bit.toTB, suffixes.tb, ); }, }; }, B(value) { return { toBit(opts = {}) { return conv( value, opts.hr || false, opts.round || false, multipliers.B.toBit, suffixes.bit, ); }, toBHr(opts = {}) { return conv( value, true, opts.round || false, multipliers.B.toBHr, suffixes.b, ); }, toKB(opts = {}) { return conv( value, opts.hr || false, opts.round || false, multipliers.B.toKB, suffixes.kb, ); }, toMB(opts = {}) { return conv( value, opts.hr || false, opts.round || false, multipliers.B.toMB, suffixes.mb, ); }, toGB(opts = {}) { return conv( value, opts.hr || false, opts.round || false, multipliers.B.toGB, suffixes.gb, ); }, toTB(opts = {}) { return conv( value, opts.hr || false, opts.round || false, multipliers.B.toTB, suffixes.tb, ); }, }; }, KB(value) { return { toBit(opts = {}) { return conv( value, opts.hr || false, opts.round || false, multipliers.KB.toBit, suffixes.bit, ); }, toB(opts = {}) { return conv( value, opts.hr || false, opts.round || false, multipliers.KB.toB, suffixes.b, ); }, toKBHr(opts = {}) { return conv( value, true, opts.round || false, multipliers.KB.toKBHr, suffixes.kb, ); }, toMB(opts = {}) { return conv( value, opts.hr || false, opts.round || false, multipliers.KB.toMB, suffixes.mb, ); }, toGB(opts = {}) { return conv( value, opts.hr || false, opts.round || false, multipliers.KB.toGB, suffixes.gb, ); }, toTB(opts = {}) { return conv( value, opts.hr || false, opts.round || false, multipliers.KB.toTB, suffixes.tb, ); }, }; }, MB(value) { return { toBit(opts = {}) { return conv( value, opts.hr || false, opts.round || false, multipliers.MB.toBit, suffixes.bit, ); }, toB(opts = {}) { return conv( value, opts.hr || false, opts.round || false, multipliers.MB.toB, suffixes.b, ); }, toKB(opts = {}) { return conv( value, opts.hr || false, opts.round || false, multipliers.MB.toKB, suffixes.kb, ); }, toMBHr(opts = {}) { return conv( value, true, opts.round || false, multipliers.MB.toMBHr, suffixes.mb, ); }, toGB(opts = {}) { return conv( value, opts.hr || false, opts.round || false, multipliers.MB.toGB, suffixes.gb, ); }, toTB(opts = {}) { return conv( value, opts.hr || false, opts.round || false, multipliers.MB.toTB, suffixes.tb, ); }, }; }, GB(value) { return { toBit(opts = {}) { return conv( value, opts.hr || false, opts.round || false, multipliers.GB.toBit, suffixes.bit, ); }, toB(opts = {}) { return conv( value, opts.hr || false, opts.round || false, multipliers.GB.toB, suffixes.b, ); }, toKB(opts = {}) { return conv( value, opts.hr || false, opts.round || false, multipliers.GB.toKB, suffixes.kb, ); }, toMB(opts = {}) { return conv( value, opts.hr || false, opts.round || false, multipliers.GB.toMB, suffixes.mb, ); }, toGBHr(opts = {}) { return conv( value, true, opts.round || false, multipliers.GB.toGBHr, suffixes.gb, ); }, toTB(opts = {}) { return conv( value, opts.hr || false, opts.round || false, multipliers.GB.toTB, suffixes.tb, ); }, }; }, TB(value) { return { toBit(opts = {}) { return conv( value, opts.hr || false, opts.round || false, multipliers.TB.toBit, suffixes.bit, ); }, toB(opts = {}) { return conv( value, opts.hr || false, opts.round || false, multipliers.TB.toB, suffixes.b, ); }, toKB(opts = {}) { return conv( value, opts.hr || false, opts.round || false, multipliers.TB.toKB, suffixes.kb, ); }, toMB(opts = {}) { return conv( value, opts.hr || false, opts.round || false, multipliers.TB.toMB, suffixes.mb, ); }, toGB(opts = {}) { return conv( value, opts.hr || false, opts.round || false, multipliers.TB.toGB, suffixes.gb, ); }, toTBHr(opts = {}) { return conv( value, true, opts.round || false, multipliers.TB.toTBHr, suffixes.tb, ); }, }; }, }; }()); const testCases = [1, 10, 150, 1000, 74839.67346]; const HRSuffixes = Object.values(suffixes); const roundDecimals = 2; const precision = Number(`0.${'0'.repeat(roundDecimals)}5`); const SCIENTIFIC_NOT_NUMBER_REGXP = /[-+]?[0-9]*.?[0-9]+([eE][-+]?[0-9]+)?/g; const SUFFIX_REGXP = /[a-z]+$/i; const CONVERSION_TO_REGXP = /(?<=to).*(?=hr+$)|(?<=to).*(?=hr+$)?/i; for (const conversionFrom of (Object.keys(MemConv))) { for (const tCase of testCases) { const convFunc = MemConv[conversionFrom](tCase); for (const [conversionToFn, f] of Object.entries(convFunc)) { const conversionTo = (conversionToFn.match(CONVERSION_TO_REGXP) || [conversionToFn])[0]; const result = f(); const humanReadable = f({ hr: true }); const rounded = f({ round: roundDecimals }); const roundedAndHumanReadable = f({ hr: true, round: roundDecimals }); console.log({ value: tCase, from: conversionFrom, to: conversionTo, result, humanReadable, rounded, roundedAndHumanReadable, }); } } }

TSVersion

test

import assert from 'assert';

function test() {
  const testCases = [1, 10, 150, 1000, 74839.67346];
  const HRSuffixes = Object.values(suffixes);
  const roundDecimals = 2;
  const precision = Number(`0.${'0'.repeat(roundDecimals)}5`);
  const SCIENTIFIC_NOT_NUMBER_REGXP = /[-+]?[0-9]*.?[0-9]+([eE][-+]?[0-9]+)?/g;
  const SUFFIX_REGXP = /[a-z]+$/i;
  const CONVERSION_TO_REGXP = /(?<=to).*(?=hr+$)|(?<=to).*(?=hr+$)?/i;

  for (const conversionFrom of (Object.keys(MemConv) as (keyof typeof MemConv)[])) {
    for (const tCase of testCases) {
      const convFunc = MemConv[conversionFrom](tCase);
      for (const [conversionToFn, f] of Object.entries(convFunc)) {
        const conversionTo = (conversionToFn.match(CONVERSION_TO_REGXP) || [conversionToFn])[0];
        const expectedSuffix = suffixes[conversionTo.toLowerCase() as keyof typeof suffixes];
        const multiplier = multipliers[conversionFrom][conversionToFn as keyof typeof multipliers[typeof conversionFrom]];
        const expectedResult = tCase * multiplier > Number.MAX_SAFE_INTEGER
            ? Number.MAX_SAFE_INTEGER
            : tCase * multiplier;

        const result = f();
        const humanReadable = f({ hr: true });
        const rounded = f({ round: roundDecimals });
        const roundedAndHumanReadable = f({ hr: true, round: roundDecimals });

        const resHrNumber = Number((humanReadable.match(SCIENTIFIC_NOT_NUMBER_REGXP) || [''])[0]);
        const resHrSuffix = (humanReadable.match(SUFFIX_REGXP) || [0])[0];
        const resRoundHrNumber = Number((roundedAndHumanReadable.match(SCIENTIFIC_NOT_NUMBER_REGXP) || [''])[0]);
        const resRoundHrSuffix = (roundedAndHumanReadable.match(SUFFIX_REGXP) || [0])[0];

        if (/hr$/i.test(conversionToFn)) {
          const resNumber = Number((humanReadable.match(SCIENTIFIC_NOT_NUMBER_REGXP) || [''])[0]);
          const resSuffix = (humanReadable.match(SUFFIX_REGXP) || [0])[0];
          assert(typeof result === 'string');
          assert(typeof resSuffix === 'string');
          assert(typeof resRoundHrNumber === 'number');
          assert(typeof rounded === 'string');
          assert(result === humanReadable);
          assert(resSuffix === expectedSuffix);
          assert(resNumber <= expectedResult + precision && resNumber >= expectedResult - precision);
        } else {
          assert(typeof result === 'number');
          assert(result === resHrNumber);
          assert(typeof rounded === 'number');
          assert(result <= expectedResult + precision && result >= expectedResult - precision);
        }

        console.log({
          value: tCase,
          from: conversionFrom,
          to: conversionToFn,
          result,
          humanReadable,
          rounded,
          roundedAndHumanReadable,
        });

        assert(typeof resHrSuffix === 'string');
        assert(typeof resHrNumber === 'number');
        assert(resHrSuffix === expectedSuffix);
        assert(resHrSuffix === resRoundHrSuffix);
        assert(HRSuffixes.includes(resHrSuffix));
      }
    }
  }
}
test();

使用

// GB to GB humanReadable
console.log(MemConv.GB(11.1942).toGBHr()); // 11.1942GB;
// GB to MB
console.log(MemConv.GB(11.1942).toMB());// 11194.2;
// MB to MB humanReadable
console.log(MemConv.MB(11.1942).toGB({ hr: true }));// 0.011194200000000001GB;
// MB to MB humanReadable with rounding
console.log(MemConv.MB(11.1942).toGB({ hr: true, round: 3 }));// 0.011GB;

计算的另一个体现

function humanFileSize(size) {
    var i = size == 0 ? 0 : Math.floor(Math.log(size) / Math.log(1024));
    return (size / Math.pow(1024, i)).toFixed(2) * 1 + ' ' + ['B', 'kB', 'MB', 'GB', 'TB'][i];
}