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

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

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


当前回答

FileUtils。如果你的项目依赖于org.apache.commons.io, byteCountToDisplaySize(长尺寸)可以工作。

此方法的JavaDoc

其他回答

使用下面的函数来获得确切的信息。它是基于atm_cashwithdraw概念生成的。

getFullMemoryUnit(): Total: [123 MB], Max: [1 GB, 773 MB, 512 KB], Free: [120 MB, 409 KB, 304 Bytes]
public static String getFullMemoryUnit(long unit) {
    long BYTE = 1024, KB = BYTE, MB = KB * KB, GB = MB * KB, TB = GB * KB;
    long KILO_BYTE, MEGA_BYTE = 0, GIGA_BYTE = 0, TERA_BYTE = 0;
    unit = Math.abs(unit);
    StringBuffer buffer = new StringBuffer();
    if ( unit / TB > 0 ) {
        TERA_BYTE = (int) (unit / TB);
        buffer.append(TERA_BYTE+" TB");
        unit -= TERA_BYTE * TB;
    }
    if ( unit / GB > 0 ) {
        GIGA_BYTE = (int) (unit / GB);
        if (TERA_BYTE != 0) buffer.append(", ");
        buffer.append(GIGA_BYTE+" GB");
        unit %= GB;
    }
    if ( unit / MB > 0 ) {
        MEGA_BYTE = (int) (unit / MB);
        if (GIGA_BYTE != 0) buffer.append(", ");
        buffer.append(MEGA_BYTE+" MB");
        unit %= MB;
    }
    if ( unit / KB > 0 ) {
        KILO_BYTE = (int) (unit / KB);
        if (MEGA_BYTE != 0) buffer.append(", ");
        buffer.append(KILO_BYTE+" KB");
        unit %= KB;
    }
    if ( unit > 0 ) buffer.append(", "+unit+" Bytes");
    return buffer.toString();
}

我刚刚修改了facebookarchive-StringUtils的代码以获得以下格式。与使用apache.hadoop-StringUtils时得到的格式相同

getMemoryUnit(): Total: [123.0 MB], Max: [1.8 GB], Free: [120.4 MB]
public static String getMemoryUnit(long bytes) {
    DecimalFormat oneDecimal = new DecimalFormat("0.0");
    float BYTE = 1024.0f, KB = BYTE, MB = KB * KB, GB = MB * KB, TB = GB * KB;
    long absNumber = Math.abs(bytes);
    double result = bytes;
    String suffix = " Bytes";
    if (absNumber < MB) {
        result = bytes / KB;
        suffix = " KB";
    } else if (absNumber < GB) {
        result = bytes / MB;
        suffix = " MB";
    } else if (absNumber < TB) {
        result = bytes / GB;
        suffix = " GB";
    }
    return oneDecimal.format(result) + suffix;
}

以上方法的使用示例:

public static void main(String[] args) {
    Runtime runtime = Runtime.getRuntime();
    int availableProcessors = runtime.availableProcessors();

    long heapSize = Runtime.getRuntime().totalMemory();
    long heapMaxSize = Runtime.getRuntime().maxMemory();
    long heapFreeSize = Runtime.getRuntime().freeMemory();

    System.out.format("Total: [%s], Max: [%s], Free: [%s]\n", heapSize, heapMaxSize, heapFreeSize);
    System.out.format("getMemoryUnit(): Total: [%s], Max: [%s], Free: [%s]\n",
            getMemoryUnit(heapSize), getMemoryUnit(heapMaxSize), getMemoryUnit(heapFreeSize));
    System.out.format("getFullMemoryUnit(): Total: [%s], Max: [%s], Free: [%s]\n",
            getFullMemoryUnit(heapSize), getFullMemoryUnit(heapMaxSize), getFullMemoryUnit(heapFreeSize));
}

字节来获取上面的格式

Total: [128974848], Max: [1884815360], Free: [126248240]

为了以人类可读的格式显示时间,请使用函数millisToShortDHMS(长持续时间)。

如果你使用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)}")

实际上,兆字节已经足够人类阅读了。

long l = 1367343104l;
    
String s = String.format("%dm", l / 1024 / 1024);

1304米

如果在Android上,你可以简单地调用Android .text. format . formatter的一个静态方法。

https://developer.android.com/reference/android/text/format/Formatter

    public static String floatForm (double d)
    {
       return new DecimalFormat("#.##").format(d);
    }


    public static String bytesToHuman (long size)
    {
        long Kb = 1  * 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 floatForm(        size     ) + " byte";
        if (size >= Kb && size < Mb)    return floatForm((double)size / Kb) + " Kb";
        if (size >= Mb && size < Gb)    return floatForm((double)size / Mb) + " Mb";
        if (size >= Gb && size < Tb)    return floatForm((double)size / Gb) + " Gb";
        if (size >= Tb && size < Pb)    return floatForm((double)size / Tb) + " Tb";
        if (size >= Pb && size < Eb)    return floatForm((double)size / Pb) + " Pb";
        if (size >= Eb)                 return floatForm((double)size / Eb) + " Eb";

        return "???";
    }