import { round } from "es-toolkit/compat" /** * 把字节长度用为可读性强的单位表示 * * @param options.iso 是否使用国际标准单位,默认 false,使用 1024 为进制,否则使用 1000 为进制 * @param options.isoUnit 使用国际标准单位时,显示标椎单位 KiB, MiB, GiB, TiB, PiB * @param options.digit 小数位数,默认 2 * @param options.round 四舍五入到指定的小数位数,优先级高于 digit * @param options.short 不固定小数位数,保留有效数字 * @param options.unit 指定单位,只返回指定单位的值 * * @example * readableByte(100) // "100 B" * readableByte(1024) // "1.00 KB" * readableByte(4553) // "4.45 KB" * readableByte(2240000) // "2.14 MB" * readableByte(999888777660) // "931.22 GB" * readableByte(1024, { short: true }) // "1 KB" * readableByte(4553, { digit: 1 }) // "4.4 KB" * readableByte(1024, { iso: true, isoUnit: true }) // "1.02 KiB" */ export function readableByte( byteLength: number, options?: { iso?: boolean isoUnit?: boolean digit?: number short?: boolean round?: number unit?: "B" | "KB" | "MB" | "GB" | "TB" | "PB" | "KiB" | "MiB" | "GiB" | "TiB" | "PiB" } ): string { const factor = options?.iso ? 1000 : 1024 const standardUnits = ["B", "KB", "MB", "GB", "TB", "PB"] const isoUnits = ["B", "KiB", "MiB", "GiB", "TiB", "PiB"] // 确定使用的单位数组 const units = options?.iso && options?.isoUnit ? isoUnits : standardUnits // 处理指定单位的情况 if (options?.unit) { let targetUnitIndex: number // 确定单位索引和使用的单位系统 if (options.unit.includes("i")) { targetUnitIndex = isoUnits.indexOf(options.unit) // 如果指定了ISO单位,则自动使用ISO标准 options.iso = true } else { targetUnitIndex = standardUnits.indexOf(options.unit) } if (targetUnitIndex === -1) { throw new Error(`Unknown unit: ${options.unit}`) } // 计算转换值 let value = byteLength if (targetUnitIndex > 0) { value = byteLength / Math.pow(factor, targetUnitIndex) } return formatNumber(value, options) + " " + options.unit } // 自动选择最合适的单位 if (Math.abs(byteLength) < factor) { return byteLength + " B" } let unitIndex = 0 let value = byteLength while (Math.abs(value) >= factor && unitIndex < units.length - 1) { value /= factor unitIndex++ } return formatNumber(value, options) + " " + units[unitIndex] } // 格式化数字为字符串 function formatNumber(value: number, options?: { digit?: number short?: boolean round?: number }): string { if (options?.round !== undefined) { return round(value, options.round).toString() } const digits = options?.digit ?? 2 if (options?.short) { // 短格式:如果是整数,不显示小数部分 if (Math.floor(value) === value) { return value.toString() } // 否则,显示数字,但去掉尾部的0 return value.toFixed(digits).replace(/\.?0+$/, '') } return value.toFixed(digits) }