具有惯用 Scala 的人类可读格式的字节

Bytes in human-readable format with idiomatic Scala

我正在寻找惯用的 Scala 代码,将一些字节格式化为人类可读的字符串,这在向用户显示文件大小时很有用。

例如,1000 字节应格式化为 1.0 kB,49134421234 字节应格式化为 49.1 GB

格式化功能的一些要求:

我的版本:

/**
  * Converts a number of bytes into a human-readable string
  * such as `2.2 MB` or `8.0 EiB`.
  *
  * @param bytes the number of bytes we want to convert
  * @param si    if true, we use base 10 SI units where 1000 bytes are 1 kB.
  *              If false, we use base 2 IEC units where 1024 bytes are 1 KiB.
  * @return the bytes as a human-readable string
  */
def humanReadableSize(bytes: Long, si: Boolean): String = {

  // See https://en.wikipedia.org/wiki/Byte
  val (baseValue, unitStrings) =
    if (si)
      (1000, Vector("B", "kB", "MB", "GB", "TB", "PB", "EB", "ZB", "YB"))
    else
      (1024, Vector("B", "KiB", "MiB", "GiB", "TiB", "PiB", "EiB", "ZiB", "YiB"))

  def getExponent(curBytes: Long, baseValue: Int, curExponent: Int = 0): Int =
    if (curBytes < baseValue) curExponent
    else {
      val newExponent = 1 + curExponent
      getExponent(curBytes / (baseValue * newExponent), baseValue, newExponent)
    }

  val exponent = getExponent(bytes, baseValue)
  val divisor = Math.pow(baseValue, exponent)
  val unitString = unitStrings(exponent)

  // Divide the bytes and show one digit after the decimal point
  f"${bytes / divisor}%.1f $unitString"
}

使用示例:

// Result: 1.0 kB
humanReadableSize(1000, si = true)

// Result: 1000.0 B
humanReadableSize(1000, si = false)

// Result: 10.0 kB
humanReadableSize(10000, si = true)

// Result: 9.8 KiB
humanReadableSize(10000, si = false)

// Result: 49.1 GB
humanReadableSize(49134421234L, si = true)

// Result: 45.8 GiB
humanReadableSize(49134421234L, si = false)

我找到了这个替代版本,虽然它不像上面那样可选,但它又快又简单。

Source Link

def bytesToString(size: Long): String = {
val TB = 1L << 40
val GB = 1L << 30
val MB = 1L << 20
val KB = 1L << 10

val (value, unit) = {
  if (size >= 2*TB) {
    (size.asInstanceOf[Double] / TB, "TB")
  } else if (size >= 2*GB) {
    (size.asInstanceOf[Double] / GB, "GB")
  } else if (size >= 2*MB) {
    (size.asInstanceOf[Double] / MB, "MB")
  } else if (size >= 2*KB) {
    (size.asInstanceOf[Double] / KB, "KB")
  } else {
    (size.asInstanceOf[Double], "B")
  }
}
"%.1f %s".formatLocal(Locale.US, value, unit)}