Files
timi-web/src/utils/IOSize.ts
2026-01-05 15:03:44 +08:00

173 lines
3.6 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

export enum Unit {
/** B */
B = "B",
/** KB */
KB = "KB",
/** MB */
MB = "MB",
/** GB */
GB = "GB",
/** TB */
TB = "TB",
/** PB */
PB = "PB",
/** EB */
EB = "EB"
}
/** 储存单位 */
export default class IOSize {
/** 1 字节 */
public static BYTE = 1;
/** 1 KB */
public static KB = IOSize.BYTE << 10;
/** 1 MB */
public static MB = IOSize.KB << 10;
/** 1 GB */
public static GB = IOSize.MB << 10;
/** 1 TB */
public static TB = IOSize.GB << 10;
/** 1 PB */
public static PB = IOSize.TB << 10;
/** 1 EB */
public static EB = IOSize.PB << 10;
public static Unit = Unit;
/**
* <p>格式化一个储存容量,保留两位小数
* <pre>
* // 返回 100.01 KB
* format(102411, 2);
* </pre>
*
* @param size 字节大小
* @param fixed 保留小数
* @param stopUnit 停止单位
* @return
*/
public static format(size: number, fixed = 2, stopUnit?: Unit): string {
const units = Object.keys(Unit);
if (0 < size) {
for (let i = 0; i < units.length; i++, size /= 1024) {
const unit = units[i];
if (size <= 1000 || i === units.length - 1 || unit === stopUnit) {
if (i === 0) {
// 最小单位不需要小数
return size + " B";
} else {
return `${size.toFixed(fixed)} ${unit}`;
}
}
}
}
return "0 B";
}
/**
* 将格式化的储存量字符串解析为字节量
* <p>支持格式10GB, 10 GB, 1TB, 1.24 KB 等(单位不区分大小写)</p>
* <pre>
* // 返回 102400
* IOSize.parse("100 KB");
* // 返回 1073741824
* IOSize.parse("1GB");
* </pre>
*
* @param sizeStr 格式化后的储存量字符串
* @return 字节量
* @throws Error 格式无效
*/
public static parse(sizeStr: string): number {
if (!sizeStr || sizeStr.trim() === "") {
throw new Error("not found sizeStr");
}
// 正则匹配:可选符号 + 数字(含小数点)+ 可选空格 + 单位
const pattern = /([-+]?\d+(?:\.\d+)?)\s*([a-zA-Z]+)/;
const matcher = pattern.exec(sizeStr.trim());
if (matcher) {
let value: number;
try {
value = parseFloat(matcher[1]);
} catch (e) {
throw new Error("invalid number format: " + matcher[1]);
}
if (value < 0) {
throw new Error("size cannot be negative: " + value);
}
const unitStr = matcher[2].toUpperCase();
let unit: Unit;
// 先尝试精确匹配枚举
if (Object.values(Unit).includes(unitStr as Unit)) {
unit = unitStr as Unit;
} else {
// 处理单字母单位缩写K/M/G/T/P/E
switch (unitStr.charAt(0)) {
case "K":
unit = Unit.KB;
break;
case "M":
unit = Unit.MB;
break;
case "G":
unit = Unit.GB;
break;
case "T":
unit = Unit.TB;
break;
case "P":
unit = Unit.PB;
break;
case "E":
unit = Unit.EB;
break;
case "B":
unit = Unit.B;
break;
default:
throw new Error("Unknown unit: " + unitStr);
}
}
return IOSize.toBytes(value, unit);
}
// 尝试解析纯数字(无单位,默认字节)
try {
const bytes = parseInt(sizeStr.trim());
if (bytes < 0) {
throw new Error("size cannot be negative: " + bytes);
}
return bytes;
} catch (e) {
throw new Error("invalid size format: " + sizeStr);
}
}
/**
* 转换值到字节量
*
* @param value 值
* @param unit 单位
* @return 字节量
*/
private static toBytes(value: number, unit: Unit): number {
const units = Object.values(Unit);
const ordinal = units.indexOf(unit);
return Math.round(value * Math.pow(1024, ordinal));
}
}