19
public String size(int size){
    String hrSize = "";
    int k = size;
    double m = size/1024;
    double g = size/1048576;
    double t = size/1073741824;

    DecimalFormat dec = new DecimalFormat("0.00");

    if (k>0)
    {

        hrSize = dec.format(k).concat("KB");

    }
    if (m>0)
    {

        hrSize = dec.format(m).concat("MB");
    }
    if (g>0)
    {

        hrSize = dec.format(g).concat("GB");
    }
    if (t>0)
    {

        hrSize = dec.format(t).concat("TB");
    }

    return hrSize;
    }

This is a method that should return size in GB,MB, KB or TB. Input value is in KB. for example result for 1245 should be like 1.21MB but what I get is 1.00MB.

Cœur
  • 37,241
  • 25
  • 195
  • 267
pedja
  • 3,285
  • 5
  • 36
  • 48

10 Answers10

45

A modified version. Only calls format once. Includes "Bytes".

public static String formatFileSize(long size) {
    String hrSize = null;

    double b = size;
    double k = size/1024.0;
    double m = ((size/1024.0)/1024.0);
    double g = (((size/1024.0)/1024.0)/1024.0);
    double t = ((((size/1024.0)/1024.0)/1024.0)/1024.0);

    DecimalFormat dec = new DecimalFormat("0.00");

    if ( t>1 ) {
        hrSize = dec.format(t).concat(" TB");
    } else if ( g>1 ) {
        hrSize = dec.format(g).concat(" GB");
    } else if ( m>1 ) {
        hrSize = dec.format(m).concat(" MB");
    } else if ( k>1 ) {
        hrSize = dec.format(k).concat(" KB");
    } else {
        hrSize = dec.format(b).concat(" Bytes");
    }

    return hrSize;
}
bickster
  • 1,292
  • 17
  • 18
  • as of 2020 we should start to consider PB, petabyte, petabytes EB, exabyte, exabytes ZB, zettabyte, zettabytes YB, yottabyte, yottabytes – Bill'o Aug 27 '20 at 09:33
32

You are performing integer division. So the result of division is also integer. And fractional part is truncated.

so, 1245 / 1024 = 1

Change your division to floating point division: -

double m = size/1024.0;
double g = size/1048576.0;
double t = size/1073741824.0;

Also, your comparison is faulty. You should do the comparison with 1.

if (m > 1), if (t > 1), if (g > 1)

Ideally I would change your comparison to: -

    if (t > 1) {
        hrSize = dec.format(t).concat("TB");
    } else if (g > 1) {
        hrSize = dec.format(g).concat("GB");
    } else if (m > 1) {
        hrSize = dec.format(m).concat("MB");
    } else {
        hrSize = dec.format(size).concat("KB");
    }

You need to compare with the higher unit first, and then move to the lower one.

Rohit Jain
  • 209,639
  • 45
  • 409
  • 525
  • For what value you are doing it. Its not possible. – Rohit Jain Nov 24 '12 at 09:20
  • 2
    @pedja: Use `else if` instead of just `if` for `m`, `g`, and `t`, since even a small file might be 0.00000000001 TB (which is greater than zero). – Greg Hewgill Nov 24 '12 at 09:20
  • 1
    @GregHewgill.. Ah! didn't notice that. – Rohit Jain Nov 24 '12 at 09:21
  • @greg. now it returns value in kb – pedja Nov 24 '12 at 09:27
  • 1
    @pedja.. Yo should do the comparison with `1`, and you are doing it with `0`. Change all the if to `k > 1`, `g > 1`, ... – Rohit Jain Nov 24 '12 at 09:29
  • 1
    @pedja.. Check the edited post. You need to modify your `if` comparison a little bit. – Rohit Jain Nov 24 '12 at 09:36
  • No, sorry it works now. @Greg Hewgill confused me with else if. it should be just if. Thanks for help – pedja Nov 24 '12 at 09:37
  • 1
    Well, there are many possible ways to implement the function you want. It sounds like you've finally converged on an implementation that works for you. – Greg Hewgill Nov 24 '12 at 09:38
  • 1
    @pedja. No he was right. Basically, you were doing the comparison wrongly. That's why else if didn't work. You should first check if your size can fit in `TB`, if not move to `MB`, and so on.. to `KB`. See the if-else comparison I posted. That way, not all your conditions will be checked. – Rohit Jain Nov 24 '12 at 09:38
  • Yes both of you were right, i just need to reverse order, to compare tb first like you explained, or use just if – pedja Nov 24 '12 at 09:41
  • Also, don't do the division first. If the file is TB then why wasting time for the slow GB and MB division. Another way is compare the size in integer first to determine the file size is TB, GB or MB then only to one division, which will increase speed – phuclv Dec 13 '13 at 01:06
14

I love this:

public static String getDynamicSpace(long diskSpaceUsed)
{
    if (diskSpaceUsed <= 0) {
        return "0";
    }

    final String[] units = new String[] { "B", "KiB", "MiB", "GiB", "TiB" };
    int digitGroups = (int) (Math.log10(diskSpaceUsed) / Math.log10(1024));
    return new DecimalFormat("#,##0.#").format(diskSpaceUsed / Math.pow(1024, digitGroups))
            + " " + units[digitGroups];
}
Sampisa
  • 1,487
  • 2
  • 20
  • 28
  • not a safe function! Crashlytics reported: `Fatal Exception: java.lang.ArrayIndexOutOfBoundsException length=5; index=319302040` – user924 Nov 27 '20 at 11:27
  • What do you mean with "not safe"? This function is safe for reasonable numbers, and it works as intended for the purpose asked in the question (from B to TiB). If you need further sizes, you can add to the array "PiB", and "EiB" to measure pebibytes and exbibytes, until 9,223,372,036,854,775,807 bytes. For bigger numbers, the function needs a redesign. Anyway, how do you propose to fix it in order to let it be "safer" (whatever that means)? – Sampisa Dec 21 '20 at 17:21
5

The problem is that you're using integer division. Change your code to:

double m = size/1024.0;
double g = size/1048576.0;
double t = size/1073741824.0;

In your original code, double m = size/1024 would divide the integer size by 1024, truncate the result to an integer, and only then convert it to double. This is why the fractional part was getting lost.

NPE
  • 486,780
  • 108
  • 951
  • 1,012
4
class ConverterUtils{
    public static void main(String[] args) {
        System.out.println(getSize(1234567));
    }
    public static String getSize(long size) {
        String s = "";
        double kb = size / 1024;
        double mb = kb / 1024;
        double gb = mb / 1024;
        double tb = gb / 1024;
        if(size < 1024L) {
            s = size + " Bytes";
        } else if(size >= 1024 && size < (1024L * 1024)) {
            s =  String.format("%.2f", kb) + " KB";
        } else if(size >= (1024L * 1024) && size < (1024L * 1024 * 1024)) {
            s = String.format("%.2f", mb) + " MB";
        } else if(size >= (1024L * 1024 * 1024) && size < (1024L * 1024 * 1024 * 1024)) {
            s = String.format("%.2f", gb) + " GB";
        } else if(size >= (1024L * 1024 * 1024 * 1024)) {
            s = String.format("%.2f", tb) + " TB";
        }
        return s;
    }
}

To better understand - https://www.techspot.com/news/68482-quickly-convert-between-storage-size-units-kb-mb.html

Valix85
  • 773
  • 1
  • 9
  • 20
Ilya Budu
  • 119
  • 1
  • 9
3

You are performing integer division,

i.e., 31/15 will result in 2, not 2.whatever

just append the number with D or d which denotes it as a double and you will be fine

double m = size/1024D;
double g = size/1048576D;
double t = size/1073741824D;
PermGenError
  • 45,977
  • 8
  • 87
  • 106
3

Its not easy to get that right. Rohit Jain mentioned the integer operation. Also rounding can be an issue, as always rounding down may not be desirable. I would advise to go for an available solution like in the triava library.

It can format numbers with arbitrary precision, in 3 different systems (SI, IEC, JEDEC) and various output options. Here are some code examples from the triava unit tests:

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

Printing exact kilo, mega values (here with W = Watt):

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

You can pass a DecimalFormat to customize the output:

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

For arbitrary operations on kilo or mega values, you can split them into components:

UnitComponent uc = new  UnitComponent(123_345_567_789L, UnitSystem.SI);
int kilos = uc.kilo(); // 567
int gigas = uc.giga(); // 123
Christian Esken
  • 472
  • 1
  • 4
  • 11
2
public class FileSizeCalculator {

    String[] fileSizeUnits = {"bytes", "KB", "MB", "GB", "TB", "PB", "EB", "ZB", "YB"};

    public static void main(String[] args) {
        FileSizeCalculator fs = new FileSizeCalculator();
        String properFileSize = fs.calculateProperFileSize(2362232012l);
        System.out.println("Proper file size: " + properFileSize);
    }

    public String calculateProperFileSize(long noOfBytes){
        String sizeToReturn = "";// = FileUtils.byteCountToDisplaySize(bytes), unit = "";
        double bytes = noOfBytes;
        int index = 0;
        for(index = 0; index < fileSizeUnits.length; index++){
            if(bytes < 1024){
                break;
            }
            bytes = bytes / 1024;
        }
        sizeToReturn = String.valueOf(bytes) + " " + fileSizeUnits[index];
        return sizeToReturn;
    }
}

Just add more file unit (if any missing), and you will see unit size up to that unit (if your file has that much length)

Vishwajit R. Shinde
  • 465
  • 2
  • 5
  • 18
  • 1
    Very nice answer! Thank you Vishwajit – Deepak kaku Feb 21 '19 at 23:45
  • i have an issue: 2362232012 this number in Bytes is equal to 2.362232012 Gigabytes but passing the Byte number i get an error which states integer is too large?? any ideas? – Inside 4ndroid May 24 '20 at 10:16
  • 1
    @Inside4ndroid, change the data type of your number of bytes to "long" datatype. So it will not give an error. I am editing my code and changing method parameter from double to long type. – Vishwajit R. Shinde May 24 '20 at 16:58
  • Units should be KiB, MiB, etc until EiB since with a long you can't measure more than 8 exbibytes (-1 byte). – Sampisa Dec 21 '20 at 17:40
0

My basic version (you CAN define some constants instead of computing POW all the time):

public static String GetFolderSizeHuman(long aBytes)
{
  if (aBytes < 1024 * 1024) 
    return aBytes + " KB";
  else if (aBytes < Math.pow(2, 20) * 1024)
    return (int) aBytes / Math.pow(2, 20) + " MB";
  else if (aBytes < Math.pow(2, 30) * 1024 )
    return kGbTbFormatter.format(aBytes / Math.pow(2, 30)) + " GB";
  else if (aBytes < Math.pow(2, 40) * 1024)
    return kGbTbFormatter.format(aBytes / Math.pow(2, 40)) + " TB";

  else return "N/A (1TB?)";
}
Buffalo
  • 3,861
  • 8
  • 44
  • 69
0

bickster's answer works quite alright but the problem with it is that it returns results like 45.00 Bytes and 12.00 KB. In my opinion, the last decimal digits should be removed if they are zeros. So instead of 45.00 Bytes and 12.00 KB, you get 45 B and 12 KB (notice that Bytes has been changed to B. This is just for uniformity since we have KB, MB etc and not Kilobytes, Megabytes etc).

private boolean isDouble(double value) {
        if (value % 1 == 0) {
            Log.d(TAG, "value is " + value + " and is not double");
            return false;
        } else {
            Log.d(TAG, "value is " + value + " and is double");
            return true;
        }
    }

The above method simply checks if the value has zeros as decimal digits.

private String formatFileSize(long size) {
        String hrSize = null;
        double b = size;
        double k = size/1024.0;
        double m = ((size/1024.0)/1024.0);
        double g = (((size/1024.0)/1024.0)/1024.0);
        double t = ((((size/1024.0)/1024.0)/1024.0)/1024.0);

        DecimalFormat dec1 = new DecimalFormat("0.00");
        DecimalFormat dec2 = new DecimalFormat("0");
        if (t>1) {
            hrSize = isDouble(t) ? dec1.format(t).concat(" TB") : dec2.format(t).concat(" TB");
        } else if (g>1) {
            hrSize = isDouble(g) ? dec1.format(g).concat(" GB") : dec2.format(g).concat(" GB");
        } else if (m>1) {
            hrSize = isDouble(m) ? dec1.format(m).concat(" MB") : dec2.format(m).concat(" MB");
        } else if (k>1) {
            hrSize = isDouble(k) ? dec1.format(k).concat(" KB") : dec2.format(k).concat(" KB");
        } else {
            hrSize = isDouble(b) ? dec1.format(b).concat(" B") : dec2.format(b).concat(" B");
        }
        return hrSize;
    }
Community
  • 1
  • 1
X09
  • 3,827
  • 10
  • 47
  • 92