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

135

我需要以易于理解的单位显示文件大小,输出结果为字符串。

例如:

1L ==> "1 B";
1024L ==> "1 KB";
2537253L ==> "2.3 MB"

我找到了一个之前的答案(链接),但是我并不满意。

我想出了自己的解决方案,但它也有类似的缺点:

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 String.format("%.1f %s", Double.valueOf(result), unit);
}

主要问题是我对Decimalformat和/或String.format的知识有限。我希望1024L、1025L等能映射到1 KB而不是1.0 KB
因此,有两种可能性:
  1. 我更愿意使用公共库(比如Apache CommonsGoogle Guava)中的开箱即用的解决方案。
  2. 如果没有,我该如何去掉“.0”部分(不用字符串替换和正则表达式,我可以自己做)?

你可能会喜欢这里的答案[1],因为它是一个非常高效的解决方案,并且符合SI标准。[1]:https://dev59.com/XG865IYBdhLWcg3wi_Q2 - WhyNotHugo
我知道那个问题(以及被接受的答案),我还在那里发布了一个答案,引用了这个问题。不过,这个问题先出现,但是没有得到很好的答案。 - Sean Patrick Floyd
6
请看这个答案:https://dev59.com/XG865IYBdhLWcg3wi_Q2#3758880 - Aaron Digulla
如果您将最后一行更改为 return NumberFormat.getFormat("#,##0.#").format(result) + " " + unit;,它也适用于GWT!感谢这个,它仍然不在Guava中。 - tom
1
按照ISO标准,千的表示应该用小写字母"k"。 - Willem Van Onsem
显示剩余3条评论
3个回答

400
public static String readableFileSize(long size) {
    if(size <= 0) return "0";
    final String[] units = new String[] { "B", "kB", "MB", "GB", "TB" };
    int digitGroups = (int) (Math.log10(size)/Math.log10(1024));
    return new DecimalFormat("#,##0.#").format(size/Math.pow(1024, digitGroups)) + " " + units[digitGroups];
}

这将适用于最多1000 TB的数据....并且程序很简短!


3
同意,应该是正确的答案。点击这里,可以得到更好的输出结果。 - Kariem
4
最终的字符串数组单位为 units = ["B", "KB", "MB", "GB", "TB", "EB"]; // 现在它可以工作到 Long.MAX_VALUE! - Joe
32
为符合国际标准:final String[] units = new String[] { "B", "KB", "MB", "GB", "TB", "PB", "EB" }; /* 用于1000 */final String[] units = new String[] { "Bi", "KiB", "MiB", "GiB", "TiB", "PiB", "EiB" }; /* 用于1024 */ 参考:http://physics.nist.gov/cuu/Units/binary.html - Mr Ed
3
反向函数? - nefo_x
3
Android开发者的小提示:为了在Android上以漂亮易读的方式显示文件大小,您可以使用Formatter.formatShortFileSize(context,file.length()) - android developer
显示剩余14条评论

8

您可能会更容易地使用java.text.DecimalFormat。这段代码应该可以做到(只是试试看...)

new DecimalFormat("#,##0.#").format(value) + " " + unit


它是否按照要求工作? - Peter Mortensen
十年过去了,令人惊讶的是,我从未回头测试过这个。你可以自己试试看... - Robert Watkins

7

对我来说很惊讶,但基于循环的算法大约快10%。

public static String toNumInUnits(long bytes) {
    int u = 0;
    for ( ; bytes > 1024*1024; bytes >>= 10) {
        u++;
    }
    if (bytes > 1024)
        u++;
    return String.format("%.1f %cB", bytes/1024f, " kMGTPE".charAt(u));
}

4
底层的一切都基于循环。 - Evgeni Sergeev
@Evgeni Sergeev:你是什么意思?能详细说明一下吗? - Peter Mortensen
警告:此方法不适用于字节数小于等于1024的情况(结果始终为0.0 B)。您需要在方法开头添加“if (bytes <= 1024) { return String.format("%.1f B", (float) bytes); }”来解决该问题。 - xonya

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接