173 lines
3.6 KiB
TypeScript
173 lines
3.6 KiB
TypeScript
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));
|
||
}
|
||
}
|