views:

304

answers:

3

How to convert byte size into human-readable format in Java? Like 1024 should become "1 Kb" and 1024*1024 should become "1 Mb".

I am kind of sick of writing this utility method for each project. Are there any static methods in Apache Commons for this?

A: 

Not that I'm aware of but I'd vote +1 for such a feature request.

Aaron Digulla
+1 for voting this as a request
helios
This is not an answer. Please, next time consider writting it as a comment of the question.
pakore
+6  A: 

I asked the same Question recently:

Format file size as MB, GB etc

While there is no out-of-the-box answer, I can live with the solution:

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

Test code:

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

Output (on my German Locale):

1 B
4,2 KB
41,4 MB
3,3 GB

Edit: I have opened an Issue requesting this functionality for Google Guava. Perhaps someone would care to support it.

seanizer
Why is 0 an invalid file-size?
aioobe
@aioobe it was in my use case (displaying the size of an uploaded file), but arguably that's not universal
seanizer
+13  A: 

Here is my go at it (no loops and handles both SI units and binary units):

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

Example output:

                              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)
aioobe
That's pretty cool (+1)
seanizer
Don't you have the suffixes reversed? Binary units uses `"iB"`. And minor nitpick, SI kilo uses a lowercase `k`.
Jeff M
You're right. Updated. Thx!
aioobe
+1. You rock, aioobe.
Adeel Ansari
The only thing I don't like about it is that 1.0 KB could be displayed prettier as 1 KB. (Which is why I use DecimalFormat in my answer)
seanizer
I prefer 1.0 KB. Then it's clear how many significant figures the output entails. (This also seems to be the behavior of for instance the `du` command in Linux.)
aioobe