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

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

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


当前回答

你可以使用StringUtils的TraditionalBinarPrefix:

public static String humanReadableInt(long number) {
    return TraditionalBinaryPrefix.long2String(number, ””, 1);
}

其他回答

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;
}

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

我通常是这样做的:

public static String getFileSize(double size) {
    return _getFileSize(size,0,1024);
}

public static String _getFileSize(double size, int i, double base) {
    String units = " KMGTP";
    String unit = (i>0)?(""+units.charAt(i)).toUpperCase()+"i":"";
    if(size<base)
        return size +" "+unit.trim()+"B";
    else {
        size = Math.floor(size/base);
        return _getFileSize(size,++i,base);
    }
}

Kotlin版本通过扩展属性

如果您正在使用Kotlin,那么通过这些扩展名属性格式化文件大小非常容易。它是无循环的,完全基于纯数学。


HumanizeUtils.kt

import java.io.File
import kotlin.math.log2
import kotlin.math.pow

/**
 * @author aminography
 */

val File.formatSize: String
    get() = length().formatAsFileSize

val Int.formatAsFileSize: String
    get() = toLong().formatAsFileSize

val Long.formatAsFileSize: String
    get() = log2(if (this != 0L) toDouble() else 1.0).toInt().div(10).let {
        val precision = when (it) {
            0 -> 0; 1 -> 1; else -> 2
        }
        val prefix = arrayOf("", "K", "M", "G", "T", "P", "E", "Z", "Y")
        String.format("%.${precision}f ${prefix[it]}B", toDouble() / 2.0.pow(it * 10.0))
    }

用法:

println("0:          " + 0.formatAsFileSize)
println("170:        " + 170.formatAsFileSize)
println("14356:      " + 14356.formatAsFileSize)
println("968542985:  " + 968542985.formatAsFileSize)
println("8729842496: " + 8729842496.formatAsFileSize)

println("file: " + file.formatSize)

结果:

0:          0 B
170:        170 B
14356:      14.0 KB
968542985:  923.67 MB
8729842496: 8.13 GB

file: 6.15 MB

我们可以完全避免使用缓慢的Math.pow()和Math.log()方法,而不会牺牲简单性,因为单位之间的因子(例如,B, KB, MB等)是1024,即2^10。Long类有一个方便的numberofleadingzero()方法,我们可以用它来告诉大小值落在哪个单元中。

重点:大小单位的距离为10位(1024 = 2^10),这意味着最高位的位置-换句话说,前导零的数量-相差10(字节= KB*1024, KB = MB*1024,等等)。

前导零数与大小单位的相关性:

# of leading 0's Size unit
>53 B (Bytes)
>43 KB
>33 MB
>23 GB
>13 TB
>3 PB
<=3 EB

最终代码:

public static String formatSize(long v) {
    if (v < 1024) return v + " B";
    int z = (63 - Long.numberOfLeadingZeros(v)) / 10;
    return String.format("%.1f %sB", (double)v / (1L << (z*10)), " KMGTPE".charAt(z));
}

也许你可以使用下面的代码(在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";