Converting KB to MB, GB, TB dynamically
Asked Answered
C

10

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.

Cattan answered 24/11, 2012 at 9:15 Comment(0)
C
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.

Cog answered 24/11, 2012 at 9:16 Comment(11)
For what value you are doing it. Its not possible.Cog
@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).Ammamaria
@GregHewgill.. Ah! didn't notice that.Cog
@greg. now it returns value in kbCattan
@pedja.. Yo should do the comparison with 1, and you are doing it with 0. Change all the if to k > 1, g > 1, ...Cog
@pedja.. Check the edited post. You need to modify your if comparison a little bit.Cog
No, sorry it works now. @Greg Hewgill confused me with else if. it should be just if. Thanks for helpCattan
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.Ammamaria
@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.Cog
Yes both of you were right, i just need to reverse order, to compare tb first like you explained, or use just ifCattan
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 speedSolidus
F
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;
}
Feint answered 13/12, 2013 at 0:5 Comment(1)
as of 2020 we should start to consider PB, petabyte, petabytes EB, exabyte, exabytes ZB, zettabyte, zettabytes YB, yottabyte, yottabytesReaction
C
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.

Cog answered 24/11, 2012 at 9:16 Comment(11)
For what value you are doing it. Its not possible.Cog
@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).Ammamaria
@GregHewgill.. Ah! didn't notice that.Cog
@greg. now it returns value in kbCattan
@pedja.. Yo should do the comparison with 1, and you are doing it with 0. Change all the if to k > 1, g > 1, ...Cog
@pedja.. Check the edited post. You need to modify your if comparison a little bit.Cog
No, sorry it works now. @Greg Hewgill confused me with else if. it should be just if. Thanks for helpCattan
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.Ammamaria
@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.Cog
Yes both of you were right, i just need to reverse order, to compare tb first like you explained, or use just ifCattan
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 speedSolidus
B
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];
}
Bindle answered 27/9, 2017 at 14:32 Comment(2)
not a safe function! Crashlytics reported: Fatal Exception: java.lang.ArrayIndexOutOfBoundsException length=5; index=319302040Coworker
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)?Bindle
T
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.

Therapeutic answered 24/11, 2012 at 9:17 Comment(0)
P
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

Pelletier answered 7/12, 2018 at 13:30 Comment(0)
L
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;
Louque answered 24/11, 2012 at 9:17 Comment(0)
S
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
Scent answered 5/1, 2017 at 14:6 Comment(0)
I
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)

Insane answered 20/1, 2015 at 13:13 Comment(4)
Very nice answer! Thank you VishwajitSeparate
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?Fecundity
@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.Insane
Units should be KiB, MiB, etc until EiB since with a long you can't measure more than 8 exbibytes (-1 byte).Bindle
C
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?)";
}
Crum answered 28/9, 2016 at 8:37 Comment(0)
E
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;
    }
Epsilon answered 9/12, 2016 at 18:23 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.