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

Igo*_*hin 503 java formatting apache-commons

如何在Java中将字节大小转换为人类可读的格式?像1024应该变成"1 Kb"而1024*1024应该变成"1 Mb".

我有点厌倦为每个项目编写这个实用工具方法.Apache Commons中是否有任何静态方法?

aio*_*obe 1211

这是我的去处(没有循环并处理SI单位和二进制单位):

public static String humanReadableByteCount(long bytes, boolean si) {
    int unit = si ? 1000 : 1024;
    if (bytes < unit) return bytes + " B";
    int exp = (int) (Math.log(bytes) / Math.log(unit));
    String pre = (si ? "kMGTPE" : "KMGTPE").charAt(exp-1) + (si ? "" : "i");
    return String.format("%.1f %sB", bytes / Math.pow(unit, exp), pre);
}
Run Code Online (Sandbox Code Playgroud)

示例输出:

                              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)
Run Code Online (Sandbox Code Playgroud)

相关文章:Java:将字节大小格式化为人类可读格式

  • **答案完全重写。上面的许多评论已经过时了。** (35认同)
  • @Borys使用"KB"表示"1024字节"是错误的.不要那样做. (20认同)
  • 我想每个人都应该注意到,在您的项目中,客户希望看到基数2(除以1024)但具有共同前缀的值.不是KiB,MiB,GiB等.使用KB,MB,GB,TB. (17认同)
  • 我更喜欢1.0 KB.然后很清楚输出需要多少重要数字.(这似乎也是Linux中`du`命令的行为.) (12认同)
  • 读者将学习它.更好的事情,他们不熟悉,可以学到它而不是出错.写一个熟悉它的用户需要1000,而一个不熟悉的用户会想到1024. (8认同)
  • @Mazyod对于iOS开发人员,您可以使用[NSByteCountFormatter](https://developer.apple.com/library/ios/documentation/Foundation/Reference/NSByteCountFormatter_Class/index.html).例如(在swift中):`let bytes = 110592 NSByteCountFormatter.stringFromByteCount(Int64(bytes),countStyle:NSByteCountFormatterCountStyle.File)`会产生"111 KB" (5认同)
  • @KlitosKyriacou"但官员,我*不是*超速!按*我的'公里'的定义,我只有5公里/小时." (4认同)
  • 什么是kMGTPE? (3认同)
  • @MohsinSyd,这些是代表"kilo","mega","giga","terra","peta"和"exa"的角色. (3认同)
  • @endolith根据IEC标准不否认它是"错误的".但是,与MB的流行用法相比,它的使用率很少,意味着1024*1024字节.例如,Windows使用"MB".使用MiB虽然正确(根据IEC),但可能会使不熟悉它的读者感到困惑.这一切都取决于你的观众是谁.无论如何,让我们不要轻视我的主要批评,即这种方法会产生不正确的结果. (3认同)
  • @KlitosKyriacou"但我们知道这意味着什么,所以这不是一个大问题" - 我已经忘记了与那些认为他们知道他们意味着哪个单位的人谈过的次数,但当被问及他们没有提示和/或不同意他们认为他们同意的人.对于基础10使用SI单位,对基础2使用IEC,世界将是一个更好的地方. (3认同)
  • @slonik,不,kilo 是小写 k 的缩写。这是来自 nist.gov 的[官方出版物](https://www.nist.gov/pml/special-publication-330/sp-330-section-3#table7) (3认同)
  • 代码很短,但是`charAt`,`?`operator和`String.format`来获取单元不是人类可读的...... (2认同)
  • @KlitosKyriacou但是那是1000卡路里还是1024卡路里?*计量单位*是规定性的;他们否则不会工作。“ kilo-”的意思是“ 1000”已有数千年的历史了。用它来引用1024的东西是错误的。 (2认同)
  • 可能更好地使用区域设置“String.format”,例如 String.format(Locale.US, "%.1f %sB", bytes / Math.pow(unit, exp), pre) (2认同)
  • 哇:D 在你的文章中(顺便说一句,读起来真的很有趣)你写道:“在解决了所有极端情况之后,代码的可读性甚至比原始版本还要差。就我个人而言,我不会将此代码段复制到生产代码中。” 我不明白新的代码片段如何更具可读性:D 与前一个代码相比,支持此代码的其他原因是什么?表现?简洁且仍然没有舍入错误? (2认同)
  • @matvs 好吧,我承认我可能对新版本打得有点过了。它的可读性不是很好,但很明显,此时它只是一个展开的循环。首先,这个版本是_正确的_,而且我认为它比以前的版本简单得多。例如,真正时髦的浮点东西已经消失了。log/pow 的东西(写起来很有趣,但读起来并不有趣)已经消失了。si/binary 标志(这增加了复杂性,但您通常从不关心)消失了。至于性能,我不知道:-)应该有人对其进行分析。 (2认同)

小智 287

FileUtils.byteCountToDisplaySize(long size)如果您的项目可以依赖,那将会奏效org.apache.commons.io.

这个方法的JavaDoc

  • 我的项目已经有了commons-io,但最后使用了aioobe的代码,因为舍入行为(请参阅JavaDoc的链接) (15认同)
  • 不幸的是,这个功能不是语言环境感知的; 例如,在法语中,它们总是将字节称为"八位字节",因此如果您要向法国用户显示100 KB文件,则正确的标签将为100 Ko. (6认同)
  • http://stackoverflow.com/a/26502430/185022没有任何依赖Android Native (4认同)
  • 是否有一个实用程序来执行反向操作.从人类可读的字节数中获取字节数? (3认同)
  • &gt; 1 gb时,它会四舍五入到最接近的gb,这意味着您获得的精度会有所不同 (3认同)

AZ_*_*AZ_ 155

使用Android内置类

对于Android,有一个类Formatter.就像代码一样,你就完成了.

android.text.format.Formatter.formatShortFileSize(activityContext, bytes);
Run Code Online (Sandbox Code Playgroud)

它是formatFileSize(),但尝试生成更短的数字(显示更少的小数).

android.text.format.Formatter.formatFileSize(activityContext, bytes);
Run Code Online (Sandbox Code Playgroud)

格式化内容大小为字节,千字节,兆字节等形式.

  • 对于ANDROID来说应该是最好的答案.不需要额外的库.+1 (9认同)
  • 我讨厌你必须传入`Context`的事实. (8认同)
  • 在我知道之前,我正在使用接受的答案.需要注意的是,在Build.VERSION_CODES.N和更早版本中,使用1024的幂,KB = 1024字节,MB = 1,048,576字节等.从O开始,前缀用于SI系统的标准含义,所以kB = 1000字节,MB = 1,000,000字节等. (6认同)
  • 您传入Context,因此它被转换为用户的当前Locale.否则它将不是一个非常有用的功能. (5认同)
  • 对于ANDROID来说应该是最好的答案. (4认同)

icz*_*cza 50

我们可以完全避免使用慢速Math.pow()Math.log()方法而不牺牲简单性,因为单位之间的因子(例如B,KB,MB等)是1024,即2 ^ 10.该Long班有一个方便的numberOfLeadingZeros(),我们可以用它来判断哪些单元大小值落在方法.

关键点:大小单位的距离为10位(1024 = 2 ^ 10),这意味着最高1位的位置 - 或者换句话说前导零数量 - 相差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
<=2                EB
Run Code Online (Sandbox Code Playgroud)

最终代码:

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));
}
Run Code Online (Sandbox Code Playgroud)


Sea*_*oyd 24

我最近问了同一个问题:

格式化文件大小为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;
}
Run Code Online (Sandbox Code Playgroud)

测试代码:

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));
    }
}
Run Code Online (Sandbox Code Playgroud)

输出(在我的德语区域设置上):

1 B
4,2 KB
41,4 MB
3,3 GB
Run Code Online (Sandbox Code Playgroud)

编辑:我已经为Google Guava打开了一个请求此功能问题.也许有人会关心它.

  • 为什么0是无效的文件大小? (2认同)

and*_*per 7

如果您使用Android,则只需使用Formatter.formatFileSize()即可.

另类,这是基于这个热门帖子的解决方案:

  /**
   * formats the bytes to a human readable format
   *
   * @param si true if each kilo==1000, false if kilo==1024
   */
  @SuppressLint("DefaultLocale")
  public static String humanReadableByteCount(final long bytes,final boolean si)
    {
    final int unit=si ? 1000 : 1024;
    if(bytes<unit)
      return bytes+" B";
    double result=bytes;
    final String unitsToUse=(si ? "k" : "K")+"MGTPE";
    int i=0;
    final int unitsCount=unitsToUse.length();
    while(true)
      {
      result/=unit;
      if(result<unit)
        break;
      // check if we can go further:
      if(i==unitsCount-1)
        break;
      ++i;
      }
    final StringBuilder sb=new StringBuilder(9);
    sb.append(String.format("%.1f ",result));
    sb.append(unitsToUse.charAt(i));
    if(si)
      sb.append('B');
    else sb.append('i').append('B');
    final String resultStr=sb.toString();
    return resultStr;
    }
Run Code Online (Sandbox Code Playgroud)


Chr*_*fer 7

这是aioobe答案的修改版本.

变化:

  • Locale参数,因为有些语言使用.和其他语言,作为小数点.
  • 人类可读的代码

private static final String[] SI_UNITS = { "B", "kB", "MB", "GB", "TB", "PB", "EB" };
private static final String[] BINARY_UNITS = { "B", "KiB", "MiB", "GiB", "TiB", "PiB", "EiB" };

public static String humanReadableByteCount(final long bytes, final boolean useSIUnits, final Locale locale)
{
    final String[] units = useSIUnits ? SI_UNITS : BINARY_UNITS;
    final int base = useSIUnits ? 1000 : 1024;

    // When using the smallest unit no decimal point is needed, because it's the exact number.
    if (bytes < base) {
        return bytes + " " + units[0];
    }

    final int exponent = (int) (Math.log(bytes) / Math.log(base));
    final String unit = units[exponent];
    return String.format(locale, "%.1f %s", bytes / Math.pow(base, exponent), unit);
}
Run Code Online (Sandbox Code Playgroud)


Tam*_*ama 7

org.springframework.util.unit.DataSize 至少在计算上可以满足这个要求。然后一个简单的装饰器就可以了。


Lar*_*ohl 6


private static final String[] Q = new String[]{"", "K", "M", "G", "T", "P", "E"};

public String getAsString(long bytes)
{
    for (int i = 6; i > 0; i--)
    {
        double step = Math.pow(1024, i);
        if (bytes > step) return String.format("%3.1f %s", bytes / step, Q[i]);
    }
    return Long.toString(bytes);
}
Run Code Online (Sandbox Code Playgroud)


Seb*_*Hoß 6

字节单位允许您这样做:

long input1 = 1024;
long input2 = 1024 * 1024;

Assert.assertEquals("1 KiB", BinaryByteUnit.format(input1));
Assert.assertEquals("1 MiB", BinaryByteUnit.format(input2));

Assert.assertEquals("1.024 KB", DecimalByteUnit.format(input1, "#.0"));
Assert.assertEquals("1.049 MB", DecimalByteUnit.format(input2, "#.000"));

NumberFormat format = new DecimalFormat("#.#");
Assert.assertEquals("1 KiB", BinaryByteUnit.format(input1, format));
Assert.assertEquals("1 MiB", BinaryByteUnit.format(input2, format));
Run Code Online (Sandbox Code Playgroud)

我编写了另一个称为存储单元的库,该库允许您像这样进行操作:

String formattedUnit1 = StorageUnits.formatAsCommonUnit(input1, "#");
String formattedUnit2 = StorageUnits.formatAsCommonUnit(input2, "#");
String formattedUnit3 = StorageUnits.formatAsBinaryUnit(input1);
String formattedUnit4 = StorageUnits.formatAsBinaryUnit(input2);
String formattedUnit5 = StorageUnits.formatAsDecimalUnit(input1, "#.00", Locale.GERMAN);
String formattedUnit6 = StorageUnits.formatAsDecimalUnit(input2, "#.00", Locale.GERMAN);
String formattedUnit7 = StorageUnits.formatAsBinaryUnit(input1, format);
String formattedUnit8 = StorageUnits.formatAsBinaryUnit(input2, format);

Assert.assertEquals("1 kB", formattedUnit1);
Assert.assertEquals("1 MB", formattedUnit2);
Assert.assertEquals("1.00 KiB", formattedUnit3);
Assert.assertEquals("1.00 MiB", formattedUnit4);
Assert.assertEquals("1,02 kB", formattedUnit5);
Assert.assertEquals("1,05 MB", formattedUnit6);
Assert.assertEquals("1 KiB", formattedUnit7);
Assert.assertEquals("1 MiB", formattedUnit8);
Run Code Online (Sandbox Code Playgroud)

如果您要强制某个单位,请执行以下操作:

String formattedUnit9 = StorageUnits.formatAsKibibyte(input2);
String formattedUnit10 = StorageUnits.formatAsCommonMegabyte(input2);

Assert.assertEquals("1024.00 KiB", formattedUnit9);
Assert.assertEquals("1.00 MB", formattedUnit10);
Run Code Online (Sandbox Code Playgroud)


XXX*_*XXX 5

    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 "???";
    }
Run Code Online (Sandbox Code Playgroud)


Suj*_*ana 5

  private String bytesIntoHumanReadable(long bytes) {
        long kilobyte = 1024;
        long megabyte = kilobyte * 1024;
        long gigabyte = megabyte * 1024;
        long terabyte = gigabyte * 1024;

        if ((bytes >= 0) && (bytes < kilobyte)) {
            return bytes + " B";

        } else if ((bytes >= kilobyte) && (bytes < megabyte)) {
            return (bytes / kilobyte) + " KB";

        } else if ((bytes >= megabyte) && (bytes < gigabyte)) {
            return (bytes / megabyte) + " MB";

        } else if ((bytes >= gigabyte) && (bytes < terabyte)) {
            return (bytes / gigabyte) + " GB";

        } else if (bytes >= terabyte) {
            return (bytes / terabyte) + " TB";

        } else {
            return bytes + " Bytes";
        }
    }
Run Code Online (Sandbox Code Playgroud)

  • 你总是可以让事情变得更加“高效”,但在某些时候,这可能会以人类读者的清晰度为代价。我认为这是一个很好的权衡。现在,如果您需要支持 2 倍或 3 倍的单位(例如“PB”、“EB”、“ZB”、“YB”),就像其他一些答案一样,那么我认为干燥会是一个很好的选择方法。值得庆幸的是,在我们的应用程序中,我们永远不会超过“GB”,更不用说“TB”了。 (2认同)

ami*_*phy 5

Kotlin Version通过Extension Property

如果您正在使用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))
    }
Run Code Online (Sandbox Code Playgroud)

用法:

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

println("file: " + file.formatSize)
Run Code Online (Sandbox Code Playgroud)

结果:

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

file: 6.15 MB
Run Code Online (Sandbox Code Playgroud)