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

How to convert byte size into human readable format in java?

在Java中如何将字节大小转换为人类可读格式?像1024应该变成"1KB",而1024*1024应该变成"1MB"。

我有点讨厌为每个项目编写这种实用方法。在ApacheCommons中,是否有任何静态方法可以实现这一点?


这是我的做法(没有循环和处理国际单位和二进制单位):

1
2
3
4
5
6
7
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);
}

实例输出:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
                              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)

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


如果您的项目可以依赖于org.apache.commons.io,那么FileUtils.byteCountToDisplaySize(long size)将起作用。

此方法的JavaDoc


使用Android内置类

对于Android,有一个类格式化程序。只有一个类似的代码,你就完成了。

1
android.text.format.Formatter.formatShortFileSize(activityContext, bytes);

它与formatFileSize()类似,但试图生成较短的数字(显示较少的小数)。

1
android.text.format.Formatter.formatFileSize(activityContext, bytes);

将内容大小格式化为字节、千字节、兆字节等形式。


我们可以完全避免使用缓慢的Math.pow()Math.log()方法,而不会牺牲简单性,因为单元之间的系数(如b、kb、mb等)是1024,即2^10。Long类有一个方便的numberOfLeadingZeros()方法,我们可以用它来判断大小值属于哪个单位。

关键点:大小单位的距离为10位(1024=2^10),表示最高1位的位置,或者换句话说,前导零的数量相差10位(字节=kb*1024,kb=mb*1024等)。

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

1
2
3
4
5
6
7
8
9
# of leading 0's   Size unit
-------------------------------
>53                B (Bytes)
>43                KB
>33                MB
>23                GB
>13                TB
>3                 PB
<=2                EB

最终代码:

1
2
3
4
5
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));
}


我最近问了同样的问题:

将文件大小格式化为MB、GB等

虽然没有现成的答案,但我可以接受这个解决方案:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
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;
}

测试代码:

1
2
3
4
5
6
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
2
3
4
1 B
4,2 KB
41,4 MB
3,3 GB

编辑:我打开了一个问题,要求谷歌瓜娃提供这个功能。也许有人愿意支持它。


这是Aiobe答案的修改版本。

变化:

  • Locale参数,因为有些语言使用.和其他,作为小数点。
  • 人类可读代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
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);
}

如果使用Android,只需使用formatter.formatfilesize()。

另外,这里有一个基于这个流行帖子的解决方案:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
  /**
   * 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;
    }


1
2
3
4
5
6
7
8
9
10
11
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);
}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
    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"???";
    }


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
  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";
        }
    }


字节单位允许您这样做:

1
2
3
4
5
6
7
8
9
10
11
12
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));

我写了另一个库,叫做存储单元,它允许你这样做:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
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);

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

1
2
3
4
5
String formattedUnit9 = StorageUnits.formatAsKibibyte(input2);
String formattedUnit10 = StorageUnits.formatAsCommonMegabyte(input2);

Assert.assertEquals("1024.00 KiB", formattedUnit9);
Assert.assertEquals("1.00 MB", formattedUnit10);


现在有一个库包含单位格式。我将它添加到Triava库中,因为现有的唯一一个库似乎是用于Android的库。

它可以在3个不同的系统(si、iec、jedec)和各种输出选项中以任意精度格式化数字。以下是Triava单元测试的一些代码示例:

1
2
3
4
UnitFormatter.formatAsUnit(1126, UnitSystem.SI,"B");
// ="1.13kB"
UnitFormatter.formatAsUnit(2094, UnitSystem.IEC,"B");
// ="2.04KiB"

打印精确的千、兆值(此处W=瓦):

1
2
UnitFormatter.formatAsUnits(12_000_678, UnitSystem.SI,"W",",");
// ="12MW, 678W"

您可以通过decimalFormat自定义输出:

1
2
UnitFormatter.formatAsUnit(2085, UnitSystem.IEC,"B", new DecimalFormat("0.0000"));
// ="2.0361KiB"

对于对kilo或mega值的任意操作,可以将其拆分为组件:

1
2
3
UnitComponent uc = new  UnitComponent(123_345_567_789L, UnitSystem.SI);
int kilos = uc.kilo(); // 567
int gigas = uc.giga(); // 123

我知道更新这篇文章太迟了!但我对这件事很感兴趣:

创建接口:

1
2
3
4
public interface IUnits {
     public String format(long size, String pattern);
     public long getUnitSize();
}

创建StorageUnits类:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
import java.text.DecimalFormat;

public class StorageUnits {
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;

enum Unit implements IUnits {
    TERA_BYTE {
        @Override
        public String format(long size, String pattern) {
            return format(size, getUnitSize(),"TB", pattern);
        }
        @Override
        public long getUnitSize() {
            return T;
        }
        @Override
        public String toString() {
            return"Terabytes";
        }
    },
    GIGA_BYTE {
        @Override
        public String format(long size, String pattern) {
            return format(size, getUnitSize(),"GB", pattern);
        }
        @Override
        public long getUnitSize() {
            return G;
        }
        @Override
        public String toString() {
            return"Gigabytes";
        }
    },
    MEGA_BYTE {
        @Override
        public String format(long size, String pattern) {
            return format(size, getUnitSize(),"MB", pattern);
        }
        @Override
        public long getUnitSize() {
            return M;
        }
        @Override
        public String toString() {
            return"Megabytes";
        }
    },
    KILO_BYTE {
        @Override
        public String format(long size, String pattern) {
            return format(size, getUnitSize(),"kB", pattern);
        }
        @Override
        public long getUnitSize() {
            return K;
        }
        @Override
        public String toString() {
            return"Kilobytes";
        }

    };
    String format(long size, long base, String unit, String pattern) {
        return new DecimalFormat(pattern).format(
                Long.valueOf(size).doubleValue() / Long.valueOf(base).doubleValue()
        ) + unit;
    }
}

public static String format(long size, String pattern) {
    for(Unit unit : Unit.values()) {
        if(size >= unit.getUnitSize()) {
            return unit.format(size, pattern);
        }
    }
    return ("???(" + size +")???");
}

public static String format(long size) {
    return format(size,"#,##0.#");
}
}

称之为:

1
2
3
4
5
6
class Main {
    public static void main(String... args) {
         System.out.println(StorageUnits.format(21885));
         System.out.println(StorageUnits.format(2188121545L));
    }
}

输出:

1
2
21.4kB
2GB

这里是上面关于Java正确一致答案的C...NET等价物。(下面还有一个代码较短的代码)

1
2
3
4
5
6
7
8
9
    public static String BytesNumberToHumanReadableString(long bytes, bool SI1000orBinary1024)
    {

        int unit = SI1000orBinary1024 ? 1000 : 1024;
        if (bytes < unit) return bytes +" B";
        int exp = (int)(Math.Log(bytes) / Math.Log(unit));
        String pre = (SI1000orBinary1024 ?"kMGTPE" :"KMGTPE")[(exp - 1)] + (SI1000orBinary1024 ?"" :"i");
        return String.Format("{0:F1} {1}B", bytes / Math.Pow(unit, exp), pre);
    }

从技术上讲,如果我们坚持使用国际单位制,这个程序适用于任何经常使用的数字。专家们还有许多其他的好答案。假设您正在网格视图上进行数字的数据绑定,从中检查性能优化的例程是值得的。

PS:发布是因为这个问题/答案在我做C项目的时候出现在谷歌搜索上。


在不太可能的情况下,它可以节省一些时间,或者只是为了好玩,这里有一个Go版本。为了简单起见,我只包括二进制输出案例。

1
2
3
4
5
6
7
8
9
10
11
12
func sizeOf(bytes int64) string {
    const unit = 1024
    if bytes < unit {
        return fmt.Sprintf("%d B", bytes)
    }

    fb := float64(bytes)
    exp := int(math.Log(fb) / math.Log(unit))
    pre :="KMGTPE"[exp-1]
    div := math.Pow(unit, float64(exp))
    return fmt.Sprintf("%.1f %ciB", fb / div, pre)
}


1
2
3
4
5
6
7
8
9
10
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("正确格式的文件大小:"+bytes+""+filesizeUnits[索引]);sizeToReturn=string.valueof(bytes)+""+filesizeUnits[索引];返回大小返回;}


使用下面的函数可以获得准确的信息,这些信息是根据ATM_CashWithdrawl概念生成的。

1
getFullMemoryUnit(): Total: [123 MB], Max: [1 GB, 773 MB, 512 KB], Free: [120 MB, 409 KB, 304 Bytes]
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
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时将获得相同的格式

1
getMemoryUnit(): Total: [123.0 MB], Max: [1.8 GB], Free: [120.4 MB]
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
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;
}

上述方法的示例用法:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
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]
"
, heapSize, heapMaxSize, heapFreeSize);
    System.out.format("getMemoryUnit(): Total: [%s], Max: [%s], Free: [%s]
"
,
            getMemoryUnit(heapSize), getMemoryUnit(heapMaxSize), getMemoryUnit(heapFreeSize));
    System.out.format("getFullMemoryUnit(): Total: [%s], Max: [%s], Free: [%s]
"
,
            getFullMemoryUnit(heapSize), getFullMemoryUnit(heapMaxSize), getFullMemoryUnit(heapFreeSize));
}

高于格式的字节数

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

为了以人类可读的格式显示时间,请使用此函数millisToShortDHMS(long duration)


你试过JSR 363吗?它的单元扩展模块,比如unicode cldr(在github:uom系统中),为您做所有这些。

您可以使用每个实现中包含的MetricPrefixBinaryPrefix(与上面的一些示例类似),如果您在印度或附近国家生活和工作,IndianPrefix(也在UOM系统的通用模块中)也允许您使用和格式化"crore bytes"或"lakh bytes"。


您可以使用StringUtils的TraditionalBinarPrefix

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


1
2
3
4
5
filename=filedilg.getSelectedFile().getAbsolutePath();
File file=new File(filename);

String disp=FileUtils.byteCountToDisplaySize(file.length());
System.out.println("THE FILE PATH IS"+file+"THIS File SIZE IS IN MB"+disp);

也许您可以使用此代码(在C中):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
        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";

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
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);
                }
            }
        }
    }
}