跳转到内容

格式化字节

基础版

ts
/**
 * 格式化字节
 * @param bytes 字节数
 * @param decimals 小数位数
 * @returns 格式化后的字节数
 */
export function formatBytes(bytes: number, decimals = 2) {
  if (bytes <= 0) return '0B'
  const k = 1024
  const dm = decimals < 0 ? 0 : decimals
  const units = ['', 'K', 'M', 'G', 'T', 'P', 'E', 'Z', 'Y']
  const i = Math.min(
    Math.floor(Math.log(bytes) / Math.log(k)),
    units.length - 1,
  )
  return parseFloat((bytes / Math.pow(k, i)).toFixed(dm)) + units[i] + 'B'
}
使用示例
ts
console.log(formatBytes(0)) // "0B"
console.log(formatBytes(-100)) // "0B"
console.log(formatBytes(512)) // "512B"
console.log(formatBytes(1024)) // "1KB"
console.log(formatBytes(1536)) // "1.5KB"
console.log(formatBytes(12345)) // "12.06KB"
console.log(formatBytes(1048576)) // "1MB"
console.log(formatBytes(1073741824)) // "1GB"
console.log(formatBytes(1234567890)) // "1.15GB"

// 测试不同的小数位数
console.log(formatBytes(1500, 0)) // "1KB"
console.log(formatBytes(1500, 1)) // "1.5KB"
console.log(formatBytes(1500, 3)) // "1.465KB"
console.log(formatBytes(1500, 5)) // "1.46484KB"
console.log(formatBytes(1000000, 3)) // "976.563KB"

// 测试负小数位数(会被视为0)
console.log(formatBytes(1500, -1)) // "1KB"
console.log(formatBytes(1500, -2)) // "1KB"

while 版

ts
/**
 * 格式化字节
 */
export function formatBytes(bytes: number, decimals = 2) {
  if (bytes <= 0) return '0B'
  const dm = decimals < 0 ? 0 : decimals
  const units = ['', 'K', 'M', 'G', 'T', 'P', 'E', 'Z', 'Y']
  let i = 0
  while (bytes > 1024) {
    bytes = bytes / 1024
    i++
    if (i >= units.length - 1) break
  }
  return `${bytes.toFixed(dm).replace(/\.?0+$/, '')}${units[i]}B`
}

高级版

ts
interface FormatBytesOptions {
  /**
   * 小数位数
   * @default 2
   */
  decimals?: number
  /**
   * 后缀
   * @default 'B'
   */
  suffix?: string
  /**
   * 去除结尾多余的 0(1.00KB -> 1KB  1.50KB -> 1.5KB)
   * @default false
   */
  trim?: boolean
  /**
   * 进制基数
   * @default 1024
   */
  radix?: number
  /**
   * 以比特为单位计算 (1b = 8bit)
   * @default false
   */
  bits?: boolean
}

/**
 * 格式化字节数
 * @param bytes 字节数
 * @param options 格式化选项
 * @returns 格式化后的字节数
 *
 * @example
 * formatBytes(12345) // 12.06KB
 * formatBytes(12345, { decimals: 0 }) // 12KB
 * formatBytes(1048576, { suffix: 'bps/s', trim: true, bits: true }) // 8Mbps/s
 */
export function formatBytes(bytes: number, options?: FormatBytesOptions) {
  const {
    decimals = 2,
    suffix = 'B',
    trim = false,
    radix = 1024,
    bits = false,
  } = options || {}

  const units = ['', 'K', 'M', 'G', 'T', 'P', 'E', 'Z', 'Y']
  const trimRegex = /\.?0+$/

  const dm = decimals < 0 ? 0 : decimals

  let text: string
  let unit = ''

  if (bits) {
    bytes = bytes * 8
  }

  if (bytes > 0) {
    const i = Math.min(
      Math.floor(Math.log(bytes) / Math.log(radix)),
      units.length - 1,
    )
    text = (bytes / Math.pow(radix, i)).toFixed(dm)
    unit = units[i] || ''
  } else {
    text = bytes.toFixed(dm)
  }

  if (trim) {
    text = text.replace(trimRegex, '')
  }

  return text + unit + suffix
}
使用示例
ts
formatBytes(12345) // 12.06KB
formatBytes(-12345) // -12345.00B
formatBytes(0) // 0.00B
formatBytes(1024) // 1.00KB
formatBytes(12345, { decimals: 0 }) // 12KB
formatBytes(12345, { decimals: 4 }) // 12.0557KB
formatBytes(1024, { trim: true }) // 1KB
formatBytes(1536, { trim: true }) // 1.5KB
formatBytes(1048576, { suffix: 'B/s', trim: true }) // 1MB/s
formatBytes(1048576, { suffix: 'bps/s', trim: true, bits: true }) // 8Mbps/s
formatBytes(1048576, { radix: 1000 }) // 1.05MB