Rectangle 27 1036

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

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.)

I think every one should note that in your project customer want see values in base 2 (devided by 1024) but with common prefix. Not KiB, MiB, GiB etc. Use KB, MB, GB, TB for it.

let bytes = 110592 NSByteCountFormatter.stringFromByteCount(Int64(bytes), countStyle: NSByteCountFormatterCountStyle.File)

Readers will learn it. Better something they are unfamiliar with and can learn it than having something wrong. Writing KB a user who is familiar with it will expect 1000 and a user who is unfamiliar will expect 1024.

formatting - How to convert byte size into human readable format in ja...

java formatting apache-commons
Rectangle 27 1025

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

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.)

I think every one should note that in your project customer want see values in base 2 (devided by 1024) but with common prefix. Not KiB, MiB, GiB etc. Use KB, MB, GB, TB for it.

let bytes = 110592 NSByteCountFormatter.stringFromByteCount(Int64(bytes), countStyle: NSByteCountFormatterCountStyle.File)

Readers will learn it. Better something they are unfamiliar with and can learn it than having something wrong. Writing KB a user who is familiar with it will expect 1000 and a user who is unfamiliar will expect 1024.

formatting - How to convert byte size into human readable format in ja...

java formatting apache-commons
Rectangle 27 223

FileUtils.byteCountToDisplaySize(long size)
org.apache.commons.io

I already have commons-io on my project, but ended up using aioobe's code, because of the rounding behavior (see the link for JavaDoc)

is there a utility to do the reverse operation. Getting byte count from human readable byte count?

Unfortunately this function is not locale-aware; in French, for example, they always call bytes "octets" so if you're going to display a 100 KB file to a French user the correct label would be 100 Ko.

@Tacroy You can get octets output with the UnitFormatter in the triava library. You can pass any unit for bytes, Watts or octets. Example, slightly modified from the examples in github.com/trivago/triava: UnitFormatter.formatAsUnit(1126, UnitSystem.SI, "o"); // = "1.13 ko" More examples in: stackoverflow.com/questions/3758606/

formatting - How to convert byte size into human readable format in ja...

java formatting apache-commons
Rectangle 27 218

FileUtils.byteCountToDisplaySize(long size)
org.apache.commons.io

I already have commons-io on my project, but ended up using aioobe's code, because of the rounding behavior (see the link for JavaDoc)

is there a utility to do the reverse operation. Getting byte count from human readable byte count?

Unfortunately this function is not locale-aware; in French, for example, they always call bytes "octets" so if you're going to display a 100 KB file to a French user the correct label would be 100 Ko.

@Tacroy You can get octets output with the UnitFormatter in the triava library. You can pass any unit for bytes, Watts or octets. Example, slightly modified from the examples in github.com/trivago/triava: UnitFormatter.formatAsUnit(1126, UnitSystem.SI, "o"); // = "1.13 ko" More examples in: stackoverflow.com/questions/3758606/

formatting - How to convert byte size into human readable format in ja...

java formatting apache-commons
Rectangle 27 107

For Android there is a class Formatter. Just one like of code and you are done.

It is Like formatFileSize(), but trying to generate shorter numbers (showing fewer decimals).

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

Formats a content size to be in the form of bytes, kilobytes, megabytes, etc.

I hate the fact you have to pass in Context.

You pass in Context so it's translated to the user's current Locale. Otherwise it wouldn't be a very useful function.

formatting - How to convert byte size into human readable format in ja...

java formatting apache-commons
Rectangle 27 104

For Android there is a class Formatter. Just one like of code and you are done.

It is Like formatFileSize(), but trying to generate shorter numbers (showing fewer decimals).

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

Formats a content size to be in the form of bytes, kilobytes, megabytes, etc.

I hate the fact you have to pass in Context.

You pass in Context so it's translated to the user's current Locale. Otherwise it wouldn't be a very useful function.

formatting - How to convert byte size into human readable format in ja...

java formatting apache-commons
Rectangle 27 30

We can completely avoid using the slow Math.pow() and Math.log() methods without sacrificing simplicity since the factor between the units (e.g. B, KB, MB etc.) is 1024 which is 2^10. The Long class has a handy numberOfLeadingZeros() method which we can use to tell in which unit the size value falls.

Key point: Size units have a distance of 10 bits (1024=2^10) meaning the position of the highest 1 bit - or in other words the number of leading zeros - differ by 10 (Bytes=KB*1024, KB=MB*1024 etc.).

Correlation between number of leading zeros and size unit:

# of leading 0's   Size unit
-------------------------------
>53                B (Bytes)
>43                KB
>33                MB
>23                GB
>13                TB
>3                 PB
<=2                EB
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));
}

formatting - How to convert byte size into human readable format in ja...

java formatting apache-commons
Rectangle 27 30

We can completely avoid using the slow Math.pow() and Math.log() methods without sacrificing simplicity since the factor between the units (e.g. B, KB, MB etc.) is 1024 which is 2^10. The Long class has a handy numberOfLeadingZeros() method which we can use to tell in which unit the size value falls.

Key point: Size units have a distance of 10 bits (1024=2^10) meaning the position of the highest 1 bit - or in other words the number of leading zeros - differ by 10 (Bytes=KB*1024, KB=MB*1024 etc.).

Correlation between number of leading zeros and size unit:

# of leading 0's   Size unit
-------------------------------
>53                B (Bytes)
>43                KB
>33                MB
>23                GB
>13                TB
>3                 PB
<=2                EB
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));
}

formatting - How to convert byte size into human readable format in ja...

java formatting apache-commons
Rectangle 27 20

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;
}
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 B
4,2 KB
41,4 MB
3,3 GB

@aioobe it was in my use case (displaying the size of an uploaded file), but arguably that's not universal

If you change the last line to return NumberFormat.getFormat("#,##0.#").format(result) + " " + unit; it works in GWT too! Thanks for this, it's still not in Guava.

formatting - How to convert byte size into human readable format in ja...

java formatting apache-commons
Rectangle 27 20

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;
}
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 B
4,2 KB
41,4 MB
3,3 GB

@aioobe it was in my use case (displaying the size of an uploaded file), but arguably that's not universal

If you change the last line to return NumberFormat.getFormat("#,##0.#").format(result) + " " + unit; it works in GWT too! Thanks for this, it's still not in Guava.

formatting - How to convert byte size into human readable format in ja...

java formatting apache-commons
Rectangle 27 5

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

formatting - How to convert byte size into human readable format in ja...

java formatting apache-commons
Rectangle 27 5

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

formatting - How to convert byte size into human readable format in ja...

java formatting apache-commons
Rectangle 27 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 "???";
    }

formatting - How to convert byte size into human readable format in ja...

java formatting apache-commons
Rectangle 27 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 "???";
    }

formatting - How to convert byte size into human readable format in ja...

java formatting apache-commons
Rectangle 27 5

Alternativey, here's a solution based on this popular post :

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

You seem to have an off-by-one error in your for-loop. I think it should be unitsCount and not unitsCount-1.

@aioobe but this means the loop can stop when i==unitsCount, which means i==6, which means "charAt" will fail...

if(result<unit) break; will kick in before that. No worries. (If you test it, you'll notice that you can skip the for-loop condition entirely.)

@aioobe Correct, that's because of the assumption (which is correct) that I handle "long" variable type. Also, it's based on the assumption that the units will be at least what I've written. If you use less units, it will produce weird results (will prefer less-than-1 values, rather than larger-than-1000 values).

Right, but as it stands now, it is seriously flawed.

formatting - How to convert byte size into human readable format in ja...

java formatting apache-commons
Rectangle 27 4

This is a modified version of aioobe's answer.

  • Locale parameter, because some languages use . and others , as decimal point.
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);
}

formatting - How to convert byte size into human readable format in ja...

java formatting apache-commons
Rectangle 27 4

Alternativey, here's a solution based on this popular post :

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

You seem to have an off-by-one error in your for-loop. I think it should be unitsCount and not unitsCount-1.

@aioobe but this means the loop can stop when i==unitsCount, which means i==6, which means "charAt" will fail...

if(result<unit) break; will kick in before that. No worries. (If you test it, you'll notice that you can skip the for-loop condition entirely.)

@aioobe Correct, that's because of the assumption (which is correct) that I handle "long" variable type. Also, it's based on the assumption that the units will be at least what I've written. If you use less units, it will produce weird results (will prefer less-than-1 values, rather than larger-than-1000 values).

Right, but as it stands now, it is seriously flawed.

formatting - How to convert byte size into human readable format in ja...

java formatting apache-commons
Rectangle 27 4

This is a modified version of aioobe's answer.

  • Locale parameter, because some languages use . and others , as decimal point.
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);
}

formatting - How to convert byte size into human readable format in ja...

java formatting apache-commons
Rectangle 27 2

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

formatting - How to convert byte size into human readable format in ja...

java formatting apache-commons
Rectangle 27 2

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

formatting - How to convert byte size into human readable format in ja...

java formatting apache-commons