如何在Java中将字节大小转换为人类可读的格式?

比如1024应该变成“1 Kb”,1024*1024应该变成“1 Mb”。

我有点厌倦了为每个项目写这个实用方法。在Apache Commons中有这样的静态方法吗?


当前回答

也许你可以使用下面的代码(在c#中):

long Kb = 1024;
long Mb = Kb * 1024;
long Gb = Mb * 1024;
long Tb = Gb * 1024;
long Pb = Tb * 1024;
long Eb = Pb * 1024;

if (size < Kb)  return size.ToString() + " byte";

if (size < Mb)  return (size / Kb).ToString("###.##") + " Kb.";
if (size < Gb)  return (size / Mb).ToString("###.##") + " Mb.";
if (size < Tb)  return (size / Gb).ToString("###.##") + " Gb.";
if (size < Pb)  return (size / Tb).ToString("###.##") + " Tb.";
if (size < Eb)  return (size / Pb).ToString("###.##") + " Pb.";
if (size >= Eb) return (size / Eb).ToString("###.##") + " Eb.";

return "invalid size";

其他回答

String[] fileSizeUnits = {"bytes", "KB", "MB", "GB", "TB", "PB", "EB", "ZB", "YB"};

public String calculateProperFileSize(double bytes){
    String sizeToReturn = "";
    int index = 0;
    for(index = 0; index < fileSizeUnits.length; index++){
        if(bytes < 1024){
            break;
        }
        bytes = bytes / 1024;
    }

    System.out.println("File size in proper format: " + bytes + " " + fileSizeUnits[index]);
    sizeToReturn = String.valueOf(bytes) + " " + fileSizeUnits[index];
    return sizeToReturn;
}

只需添加更多的文件单元(如果有任何缺失),你将看到单元大小达到该单元(如果你的文件有那么长):

如果你使用Android,你可以简单地使用Android .text.format. formatter . formatfilesize()。它的优点是易于使用,并且它取决于区域设置,以便为用户更好地显示它。缺点是它不处理EB,而且它只用于公制单位(每个Kilo是1000字节,不能作为1024字节使用)。

或者,这里有一个基于这篇热门文章的解决方案:


interface BytesFormatter {
    /**called when the type of the result to format is Long. Example: 123KB
     * @param unitPowerIndex the unit-power we need to format to. Examples: 0 is bytes, 1 is kb, 2 is mb, etc...
     * available units and their order: B,K,M,G,T,P,E
     * @param isMetric true if each kilo==1000, false if kilo==1024
     * */
    fun onFormatLong(valueToFormat: Long, unitPowerIndex: Int, isMetric: Boolean): String

    /**called when the type of the result to format is Double. Example: 1.23KB
     * @param unitPowerIndex the unit-power we need to format to. Examples: 0 is bytes, 1 is kb, 2 is mb, etc...
     * available units and their order: B,K,M,G,T,P,E
     * @param isMetric true if each kilo==1000, false if kilo==1024
     * */
    fun onFormatDouble(valueToFormat: Double, unitPowerIndex: Int, isMetric: Boolean): String
}

/**
 * formats the bytes to a human readable format, by providing the values to format later in the unit that we've found best to fit it
 *
 * @param isMetric true if each kilo==1000, false if kilo==1024
 * */
fun bytesIntoHumanReadable(
    @IntRange(from = 0L) bytesToFormat: Long, bytesFormatter: BytesFormatter,
    isMetric: Boolean = true
): String {
    val units = if (isMetric) 1000L else 1024L
    if (bytesToFormat < units)
        return bytesFormatter.onFormatLong(bytesToFormat, 0, isMetric)
    var bytesLeft = bytesToFormat
    var unitPowerIndex = 0
    while (unitPowerIndex < 6) {
        val newBytesLeft = bytesLeft / units
        if (newBytesLeft < units) {
            val byteLeftAsDouble = bytesLeft.toDouble() / units
            val needToShowAsInteger =
                byteLeftAsDouble == (bytesLeft / units).toDouble()
            ++unitPowerIndex
            if (needToShowAsInteger) {
                bytesLeft = newBytesLeft
                break
            }
            return bytesFormatter.onFormatDouble(byteLeftAsDouble, unitPowerIndex, isMetric)
        }
        bytesLeft = newBytesLeft
        ++unitPowerIndex
    }
    return bytesFormatter.onFormatLong(bytesLeft, unitPowerIndex, isMetric)
}

Sample usage:

// val valueToTest = 2_000L
// val valueToTest = 2_000_000L
// val valueToTest = 2_000_000_000L
// val valueToTest = 9_000_000_000_000_000_000L
// val valueToTest = 9_200_000_000_000_000_000L
val bytesToFormat = Random.nextLong(Long.MAX_VALUE)
val bytesFormatter = object : BytesFormatter {
    val numberFormat = NumberFormat.getNumberInstance(Locale.ROOT).also {
        it.maximumFractionDigits = 2
        it.minimumFractionDigits = 0
    }

    private fun formatByUnit(formattedNumber: String, threePowerIndex: Int, isMetric: Boolean): String {
        val sb = StringBuilder(formattedNumber.length + 4)
        sb.append(formattedNumber)
        val unitsToUse = "B${if (isMetric) "k" else "K"}MGTPE"
        sb.append(unitsToUse[threePowerIndex])
        if (threePowerIndex > 0)
            if (isMetric) sb.append('B') else sb.append("iB")
        return sb.toString()
    }

    override fun onFormatLong(valueToFormat: Long, unitPowerIndex: Int, isMetric: Boolean): String {
        return formatByUnit(String.format("%,d", valueToFormat), unitPowerIndex, isMetric)
    }

    override fun onFormatDouble(valueToFormat: Double, unitPowerIndex: Int, isMetric: Boolean): String {
        //alternative for using numberFormat :
        //val formattedNumber = String.format("%,.2f", valueToFormat).let { initialFormattedString ->
        //    if (initialFormattedString.contains('.'))
        //        return@let initialFormattedString.dropLastWhile { it == '0' }
        //    else return@let initialFormattedString
        //}
        return formatByUnit(numberFormat.format(valueToFormat), unitPowerIndex, isMetric)
    }
}
Log.d("AppLog", "formatting of $bytesToFormat bytes (${String.format("%,d", bytesToFormat)})")
Log.d("AppLog", bytesIntoHumanReadable(bytesToFormat, bytesFormatter))
Log.d("AppLog", "Android:${android.text.format.Formatter.formatFileSize(this, bytesToFormat)}")

我最近问了同样的问题:

格式文件大小为MB, GB等。

虽然没有开箱即用的答案,但我可以接受这个解决方案:

private static final long K = 1024;
private static final long M = K * K;
private static final long G = M * K;
private static final long T = G * K;

public static String convertToStringRepresentation(final long value){
    final long[] dividers = new long[] { T, G, M, K, 1 };
    final String[] units = new String[] { "TB", "GB", "MB", "KB", "B" };
    if(value < 1)
        throw new IllegalArgumentException("Invalid file size: " + value);
    String result = null;
    for(int i = 0; i < dividers.length; i++){
        final long divider = dividers[i];
        if(value >= divider){
            result = format(value, divider, units[i]);
            break;
        }
    }
    return result;
}

private static String format(final long value,
    final long divider,
    final String unit){
    final double result =
        divider > 1 ? (double) value / (double) divider : (double) value;
    return new DecimalFormat("#,##0.#").format(result) + " " + unit;
}

测试代码:

public static void main(final String[] args){
    final long[] l = new long[] { 1l, 4343l, 43434334l, 3563543743l };
    for(final long ll : l){
        System.out.println(convertToStringRepresentation(ll));
    }
}

输出(在我的德语地区):

1 B
4,2 KB
41,4 MB
3,3 GB

我已经打开了一个问题,要求谷歌番石榴的这个功能。也许有人愿意支持它。

public String humanReadable(long size) {
    long limit = 10 * 1024;
    long limit2 = limit * 2 - 1;
    String negative = "";
    if(size < 0) {
        negative = "-";
        size = Math.abs(size);
    }

    if(size < limit) {
        return String.format("%s%s bytes", negative, size);
    } else {
        size = Math.round((double) size / 1024);
        if (size < limit2) {
            return String.format("%s%s kB", negative, size);
        } else {
            size = Math.round((double)size / 1024);
            if (size < limit2) {
                return String.format("%s%s MB", negative, size);
            } else {
                size = Math.round((double)size / 1024);
                if (size < limit2) {
                    return String.format("%s%s GB", negative, size);
                } else {
                    size = Math.round((double)size / 1024);
                        return String.format("%s%s TB", negative, size);
                }
            }
        }
    }
}

有趣的事实:这里发布的原始代码片段是Stack Overflow上被复制最多的Java代码片段,它是有缺陷的。它被修好了,但却变得一团糟。 本文的完整故事:有史以来复制最多的堆栈溢出代码片段是有缺陷的!

来源:格式化字节大小到人类可读的格式|编程。指南

SI(1 k = 1,000)

public static String humanReadableByteCountSI(long bytes) {
    if (-1000 < bytes && bytes < 1000) {
        return bytes + " B";
    }
    CharacterIterator ci = new StringCharacterIterator("kMGTPE");
    while (bytes <= -999_950 || bytes >= 999_950) {
        bytes /= 1000;
        ci.next();
    }
    return String.format("%.1f %cB", bytes / 1000.0, ci.current());
}

二进制(1's = 1,024)

public static String humanReadableByteCountBin(long bytes) {
    long absB = bytes == Long.MIN_VALUE ? Long.MAX_VALUE : Math.abs(bytes);
    if (absB < 1024) {
        return bytes + " B";
    }
    long value = absB;
    CharacterIterator ci = new StringCharacterIterator("KMGTPE");
    for (int i = 40; i >= 0 && absB > 0xfffccccccccccccL >> i; i -= 10) {
        value >>= 10;
        ci.next();
    }
    value *= Long.signum(bytes);
    return String.format("%.1f %ciB", value / 1024.0, ci.current());
}

示例输出:

                             SI     BINARY

                  0:        0 B        0 B
                 27:       27 B       27 B
                999:      999 B      999 B
               1000:     1.0 kB     1000 B
               1023:     1.0 kB     1023 B
               1024:     1.0 kB    1.0 KiB
               1728:     1.7 kB    1.7 KiB
             110592:   110.6 kB  108.0 KiB
            7077888:     7.1 MB    6.8 MiB
          452984832:   453.0 MB  432.0 MiB
        28991029248:    29.0 GB   27.0 GiB
      1855425871872:     1.9 TB    1.7 TiB
9223372036854775807:     9.2 EB    8.0 EiB   (Long.MAX_VALUE)