功能说明
该示例把字节数格式化成人类可读的字符串,例如 1536 变成 1.5 KiB。它同时支持 IEC 的 1024 进制与 SI 的 1000 进制,适合构建日志、CLI 输出、上传进度和存储配额展示。负数会保留符号,零会直接显示为 0 B,不会出现 0.0 B 之类多余小数。
关键代码
formatBytes 先校验输入是有限数字,再校验 base 只能是 1000 或 1024,decimals 限制在 0 到 6。循环在数值大于等于进制且还有更大单位时不断除以进制并递增单位下标。字节级别不显示小数,其他单位按 decimals 使用 toFixed。符号在取绝对值前记录,最后拼回单位与可选空格。
使用注意
1024 进制使用 KiB、MiB 等 IEC 名称,1000 进制使用 kB、MB 等 SI 名称,不要把两者混用,否则容量展示会与磁盘厂商标称不一致。toFixed 会做四舍五入,极小值可能显示为 0.0。超过 EiB 的数值会停留在最大单位,不再继续换算。输出是给人看的,不要用于需要精确字节数的计算或存储。
验证方式
断言 0 输出 0 B,1536 输出 1.5 KiB,1048576 输出 1.0 MiB。使用 base 1000、两位小数、无空格断言 1500 变成 1.50kB。测试负数保留符号、decimals 为 0 时不带小数。再传入非法 base、非数字和 NaN,断言分别抛出 RangeError 或 TypeError。
代码示例
const IEC_UNITS = ["B", "KiB", "MiB", "GiB", "TiB", "PiB", "EiB"];
const SI_UNITS = ["B", "kB", "MB", "GB", "TB", "PB", "EB"];
export function formatBytes(bytes, options = {}) {
if (typeof bytes !== "number" || !Number.isFinite(bytes)) {
throw new TypeError("bytes must be a finite number");
}
const { decimals = 1, base = 1024, space = true } = options;
if (base !== 1000 && base !== 1024) throw new RangeError("base must be 1000 or 1024");
if (!Number.isInteger(decimals) || decimals < 0 || decimals > 6) {
throw new RangeError("decimals must be an integer between 0 and 6");
}
const units = base === 1024 ? IEC_UNITS : SI_UNITS;
const sign = bytes < 0 ? "-" : "";
let value = Math.abs(bytes);
let unitIndex = 0;
while (value >= base && unitIndex < units.length - 1) {
value /= base;
unitIndex += 1;
}
const fixed = value.toFixed(unitIndex === 0 ? 0 : decimals);
return `${sign}${fixed}${space ? " " : ""}${units[unitIndex]}`;
}
console.log(formatBytes(0));
console.log(formatBytes(1536));
console.log(formatBytes(1048576));
console.log(formatBytes(1500, { base: 1000, decimals: 2, space: false }));
console.log(formatBytes(-2048, { decimals: 0 }));