655

How can I convert byte size into a 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. Is there a static method in Apache Commons for this?

Peter Mortensen
  • 30,030
  • 21
  • 100
  • 124
Igor Mukhin
  • 14,188
  • 18
  • 49
  • 60
  • 40
    If you use the standardized units, 1024 should become "1KiB" and 1024*1024 should become "1MiB". http://en.wikipedia.org/wiki/Binary_prefix – Pascal Cuoq Sep 21 '10 at 08:48
  • @Pascal: There should be several functions or an option to specify the base and the unit. – Aaron Digulla Sep 21 '10 at 08:49
  • possible duplicate of [Format file size as MB, GB etc](http://stackoverflow.com/questions/3263892/format-file-size-as-mb-gb-etc) – Aaron Digulla Sep 21 '10 at 09:52
  • 4
    @Pascal Cuoq: Thanks for the reference. I didn't realise until I read it that here in the EU we are required to use the correct prefixes by law. – JeremyP Sep 21 '10 at 10:48
  • 2
    @DerMike You mentioned that "Until such a library exists". This has now become true. :-) http://stackoverflow.com/questions/3758606/how-to-convert-byte-size-into-human-readable-format-in-java/38390338#38390338 – Christian Esken Jul 15 '16 at 13:28
  • 1
    @AaronDigulla You are right. Why was that __2 months older question__ closed as duplicate, and not this here? – hc_dev Nov 30 '19 at 15:49
  • Similar topic in Kotlin https://stackoverflow.com/q/59234916 – Ebrahim Byagowi Dec 08 '19 at 11:29
  • 1
    @hc_dev I imagine the 2-months-older question was closed because this one had far better answers. These questions were both posted in 2010, the other one wasn't closed until 2013. (SO should really have a "merge questions" feature, come to think of it, to pull the answers from both together into one place.) – FeRD Sep 08 '21 at 14:09

30 Answers30

1453

Fun fact: The original snippet posted here was the most copied Java snippet of all time on Stack Overflow, and it was flawed. It was fixed, but it got messy.

Full story in this article: The most copied Stack Overflow snippet of all time is flawed!

Source: Formatting byte size to human readable format | Programming.Guide

SI (1 k = 1,000)

public static String humanReadableByteCountSI(long bytes) {
    if (-1000 < bytes && bytes < 1000) {
        return bytes + " B";
    }
    CharacterIterator ci = new StringCharacterIterator("kMGTPE");
    while (bytes <= -999_950 || bytes >= 999_950) {
        bytes /= 1000;
        ci.next();
    }
    return String.format("%.1f %cB", bytes / 1000.0, ci.current());
}

Binary (1 Ki = 1,024)

public static String humanReadableByteCountBin(long bytes) {
    long absB = bytes == Long.MIN_VALUE ? Long.MAX_VALUE : Math.abs(bytes);
    if (absB < 1024) {
        return bytes + " B";
    }
    long value = absB;
    CharacterIterator ci = new StringCharacterIterator("KMGTPE");
    for (int i = 40; i >= 0 && absB > 0xfffccccccccccccL >> i; i -= 10) {
        value >>= 10;
        ci.next();
    }
    value *= Long.signum(bytes);
    return String.format("%.1f %ciB", value / 1024.0, ci.current());
}

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)
ivan_pozdeev
  • 31,209
  • 16
  • 94
  • 140
aioobe
  • 399,198
  • 105
  • 792
  • 807
  • 1
    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) – Sean Patrick Floyd Sep 21 '10 at 14:33
  • 14
    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 Sep 21 '10 at 14:48
  • 23
    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. – Borys May 23 '13 at 13:33
  • 6
    @Mazyod For iOS developers, you can use [NSByteCountFormatter](https://developer.apple.com/library/ios/documentation/Foundation/Reference/NSByteCountFormatter_Class/index.html). For example (in swift): `let bytes = 110592 NSByteCountFormatter.stringFromByteCount(Int64(bytes), countStyle: NSByteCountFormatterCountStyle.File)` would produce "111 KB" – duthen Aug 13 '15 at 12:39
  • 43
    @Borys Using "KB" to mean "1024 bytes" is wrong. Don't do that. – endolith Dec 07 '15 at 16:34
  • 1
    @endolith that's an example of prescriptivism vs descriptivism – Klitos Kyriacou Dec 21 '15 at 11:07
  • 8
    @KlitosKyriacou "But officer, I *wasn't* speeding! By *my* definition of 'kilometer', I was only going 5 km/h." – endolith Dec 21 '15 at 12:17
  • 1
    @endolith I think a better analogy might be the definition of calories. When a can of diet drink says it contains "Less than 1 calorie", it uses the colloquial and common definition of "calorie" - it really means kilocalorie. But we know what it means so it's not a big problem. – Klitos Kyriacou Dec 21 '15 at 12:35
  • 2
    @KlitosKyriacou But is that 1000 calories or 1024 calories? Units of measurement *are* prescriptive; they wouldn't work otherwise. "kilo-" has meant "1000" for thousands of years. Using it to refer to 1024 of something is wrong. – endolith Dec 21 '15 at 13:44
  • 6
    @endolith not denying it's "wrong" according to the IEC standard. However, its usage is rare compared to the popular usage of MB to mean 1024*1024 bytes. "MB" is used by Windows, for example. Using MiB, although correct (according to IEC), may confuse readers who are unfamiliar with it. It all depends on who your audience is. Anyway, let's not let this detract from my main criticism, which is that this method can produce incorrect results. – Klitos Kyriacou Dec 21 '15 at 14:21
  • 9
    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. – kap Apr 19 '16 at 12:35
  • 4
    @KlitosKyriacou "But we know what it means so it's not a big problem" -- I have lost count of the number of times I've spoken with people who think they knew which unit they meant but when questioned they don't have a clue and/or disagree with the person they thought they were in agreement with. Use SI units for base 10 and IEC for base 2 and the world will be a better place. – Samuel Harmer Apr 14 '17 at 14:01
  • For android developers, you can use https://stackoverflow.com/a/26502430/3940133 instead – HendraWD Jun 11 '18 at 11:08
  • 1
    Probably better to use locale-wise "String.format", e.g. String.format(Locale.US, "%.1f %sB", bytes / Math.pow(unit, exp), pre) – Bo Lu Oct 30 '19 at 11:38
  • 36
    **Answer rewritten entirely. Many of the above comments are obsolete.** – aioobe Dec 03 '19 at 00:03
  • 2
    Wow :D In your article (really fun read BTW) you've written: "After ironing out all corner cases the code is even less readable than the original version. Personally I would not copy this snippet into production code." I don't see how is the new snippet more readable :D What are the other reasons that back up this code over the previous one? Performance? Being concise and still without rounding bugs? – matvs Dec 05 '19 at 14:46
  • 2
    @matvs Ok, I admit that I might have golfed the new version a bit too far. It's not super readable, but it's fairly clear that it's nothing but an unrolled loop at this point. First of all, this version is _correct_, and I'd argue that it's far less complicated than the previous version. For example, the really funky floating point stuff is gone. The log/pow stuff (which was fun to write but not fun to read) is gone. The si/binary flag (which adds to the complexity but that you typically never care about) is gone. As for performance, I have no idea :-) Someone should profile it. – aioobe Dec 05 '19 at 15:38
  • made slashdot as most copied vulnerability, I assumed it was fixed – MichaelEvanchik Dec 06 '19 at 14:07
  • Swift version for humanReadableByteCountSI: https://stackoverflow.com/a/59218639/2430555 – Pedro Paulo Amorim Dec 06 '19 at 18:44
  • The answer based on the updated code here but in Kotlin https://stackoverflow.com/a/59234917 – Ebrahim Byagowi Dec 08 '19 at 11:30
  • This probably explains the reason why my Windows OS and Banana Pie(Ubuntu) shows different file size of the same .jar file. Of course, that can also because of Windows' poor memory management. In any case, here is another fun link: https://www.zdnet.com/article/the-most-copied-stackoverflow-java-code-snippet-contains-a-bug/ – Onat Korucu Dec 26 '19 at 14:45
  • @aioobe why u are using signum here , u are taking an absolute value already – Manu Jose Aug 27 '20 at 05:08
  • 1
    That was very nice!! – Pratik Saluja Oct 13 '20 at 14:15
  • I think it should be KB not kB, SI prefix is K as in Kg, not kg, i.e. should be uppercase – slonik Nov 12 '20 at 15:10
  • 3
    @slonik, no, kilo is abbreviated with lower-case k. This is the [official publication](https://www.nist.gov/pml/special-publication-330/sp-330-section-3#table7) from nist.gov – aioobe Nov 12 '20 at 15:22
  • 1
    `GiB` doesn't look good, for Binary it also better to use `GB` prefix instead of `GiB`, so users can understand it better – user924 Feb 03 '21 at 12:34
  • 1
    @user924 I'll just quote kap's comment from way back when, verbatim: "_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._" If developers actually USE the correct suffixes, users' understanding will mature. People **can** learn things. And as un-American as this apparently is to say, sometimes they should have to. – FeRD Sep 08 '21 at 13:33
361

FileUtils.byteCountToDisplaySize(long size) would work if your project can depend on org.apache.commons.io.

JavaDoc for this method

Zarathustra
  • 2,783
  • 4
  • 30
  • 60
user601806
  • 3,627
  • 1
  • 13
  • 2
  • 21
    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) – Iravanchi Jul 09 '12 at 12:31
  • 3
    is there a utility to do the reverse operation. Getting byte count from human readable byte count? – arunmoezhi Jun 24 '15 at 19:02
  • 6
    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 Dec 17 '15 at 15:26
  • @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 https://github.com/trivago/triava: UnitFormatter.formatAsUnit(1126, UnitSystem.SI, "o"); // = "1.13 ko" More examples in: http://stackoverflow.com/questions/3758606/how-to-convert-byte-size-into-human-readable-format-in-java/38390338#38390338 – Christian Esken Jan 05 '17 at 13:39
  • 7
    this rounds to the nearest gb when > 1 gb, which means that the precision you get out of it varies – tksfz Oct 17 '17 at 17:55
216

Use an Android built-in class

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

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

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

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

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

Peter Mortensen
  • 30,030
  • 21
  • 100
  • 124
AZ_
  • 36,879
  • 28
  • 155
  • 201
  • 14
    should be the best answer for ANDROID definitively. No extra libraries needed. +1 – dieter Apr 19 '15 at 11:37
  • 17
    I hate the fact you have to pass in `Context`. – Jared Burrows May 25 '15 at 03:50
  • How do you know that? – zionpi May 29 '15 at 03:17
  • 5
    Should be the best answer for ANDROID definitively. – Shridutt Kothari Oct 25 '15 at 17:24
  • 7
    You pass in Context so it's translated to the user's current Locale. Otherwise it wouldn't be a very useful function. – phreakhead May 13 '16 at 22:37
  • How to take 4 decimal places? 2 decimal places are not really accurate for mine.. – nani Jun 09 '16 at 07:11
  • Is it possible to force it to use a specific locale? It's just that when Arabic is used, I see Arabic digits (I use it for myself alone, for testing/debugging) – android developer Oct 15 '17 at 08:48
  • 1
    @androiddeveloper https://developer.android.com/reference/java/util/Formatter.html – AZ_ Oct 17 '17 at 06:14
  • @AZ_ That's not the same class. This is the formatter that's used for formatShortFileSize : https://developer.android.com/reference/android/text/format/Formatter.html . As you can see, the function there is static. – android developer Oct 17 '17 at 09:33
  • but it returns you String, right! you can localize that String. I guess it should work and then your can print that localized String or in the print statement you can also give localization. – AZ_ Oct 18 '17 at 11:50
  • 12
    I was using the accepted answer before I know this. Just to be noted, In Build.VERSION_CODES.N and earlier, powers of 1024 are used instead, with KB = 1024 bytes, MB = 1,048,576 bytes, etc. As of O, the prefixes are used in their standard meanings in the SI system, so kB = 1000 bytes, MB = 1,000,000 bytes, etc. – HendraWD Jun 11 '18 at 11:27
79

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

Key point: Size units have a distance of 10 bits (1024 = 2^10) meaning the position of the highest one 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

The final code:

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));
}
icza
  • 342,548
  • 56
  • 784
  • 738
28

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

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

Peter Mortensen
  • 30,030
  • 21
  • 100
  • 124
Sean Patrick Floyd
  • 284,665
  • 62
  • 456
  • 576
14
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";
    }
}
Peter Mortensen
  • 30,030
  • 21
  • 100
  • 124
Sujith Manjavana
  • 2,482
  • 4
  • 30
  • 47
  • I like this because it's easy to follow and easy to understand. – Joshua Pinter Feb 27 '18 at 17:33
  • 1
    @Joshua Pinter: Yes, but there is also a lot of redundancy. It begs for a loop and a (static) list of strings. – Peter Mortensen Aug 12 '20 at 19:01
  • 2
    You can always make things more "efficient" but at some point that can come at a cost of clarity to the human reader. I think this is a great trade off. Now, if you needed to support 2x or 3x the units (e.g. "PB", "EB", "ZB", "YB"), like some of the other answers, do, then I think DRYing things up would be a good approach. Thankfully, in our application we'll never go past "GB", let alone "TB". – Joshua Pinter Aug 12 '20 at 19:30
11

This is a modified version of aioobe's answer.

Changes:

  • Locale parameter, because some languages use . and others , as decimal point.
  • human-readable code

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);
}
Community
  • 1
  • 1
Christian Strempfer
  • 7,096
  • 6
  • 46
  • 75
  • 1
    It is a bit mixed results to pass along a Locale parameter just for the separator symbols, but then don't also localize the unit to account for languages that also use a different symbol for Bytes, like the French. – Nzall Oct 29 '19 at 08:37
  • @Nzall Do you mean the octet? Wikipedia is stating it's no longer common. Else, do you have a reference? – Christian Strempfer Oct 29 '19 at 21:33
  • as a French I confirm "octet" is still very used; french people will expect "Ko", "Mo", "Go", etc. Anyway i18n seems out of scope for OP. If you really need i18n you would probably have to use some properties files – user1075613 Aug 11 '21 at 19:12
9

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);
}
Lars Bohl
  • 991
  • 14
  • 20
8

If you use Android, you can simply use android.text.format.Formatter.formatFileSize(). The advantage is that it's easy to use it, and it depends on the locale to show it nicely for the user. The disadvantage is that it doesn't handle EB, and that it's only used for the metric units (each Kilo is 1000 bytes, without the ability to use it as 1024 bytes).

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


interface BytesFormatter {
    /**called when the type of the result to format is Long. Example: 123KB
     * @param unitPowerIndex the unit-power we need to format to. Examples: 0 is bytes, 1 is kb, 2 is mb, etc...
     * available units and their order: B,K,M,G,T,P,E
     * @param isMetric true if each kilo==1000, false if kilo==1024
     * */
    fun onFormatLong(valueToFormat: Long, unitPowerIndex: Int, isMetric: Boolean): String

    /**called when the type of the result to format is Double. Example: 1.23KB
     * @param unitPowerIndex the unit-power we need to format to. Examples: 0 is bytes, 1 is kb, 2 is mb, etc...
     * available units and their order: B,K,M,G,T,P,E
     * @param isMetric true if each kilo==1000, false if kilo==1024
     * */
    fun onFormatDouble(valueToFormat: Double, unitPowerIndex: Int, isMetric: Boolean): String
}

/**
 * formats the bytes to a human readable format, by providing the values to format later in the unit that we've found best to fit it
 *
 * @param isMetric true if each kilo==1000, false if kilo==1024
 * */
fun bytesIntoHumanReadable(
    @IntRange(from = 0L) bytesToFormat: Long, bytesFormatter: BytesFormatter,
    isMetric: Boolean = true
): String {
    val units = if (isMetric) 1000L else 1024L
    if (bytesToFormat < units)
        return bytesFormatter.onFormatLong(bytesToFormat, 0, isMetric)
    var bytesLeft = bytesToFormat
    var unitPowerIndex = 0
    while (unitPowerIndex < 6) {
        val newBytesLeft = bytesLeft / units
        if (newBytesLeft < units) {
            val byteLeftAsDouble = bytesLeft.toDouble() / units
            val needToShowAsInteger =
                byteLeftAsDouble == (bytesLeft / units).toDouble()
            ++unitPowerIndex
            if (needToShowAsInteger) {
                bytesLeft = newBytesLeft
                break
            }
            return bytesFormatter.onFormatDouble(byteLeftAsDouble, unitPowerIndex, isMetric)
        }
        bytesLeft = newBytesLeft
        ++unitPowerIndex
    }
    return bytesFormatter.onFormatLong(bytesLeft, unitPowerIndex, isMetric)
}

Sample usage:

// val valueToTest = 2_000L
// val valueToTest = 2_000_000L
// val valueToTest = 2_000_000_000L
// val valueToTest = 9_000_000_000_000_000_000L
// val valueToTest = 9_200_000_000_000_000_000L
val bytesToFormat = Random.nextLong(Long.MAX_VALUE)
val bytesFormatter = object : BytesFormatter {
    val numberFormat = NumberFormat.getNumberInstance(Locale.ROOT).also {
        it.maximumFractionDigits = 2
        it.minimumFractionDigits = 0
    }

    private fun formatByUnit(formattedNumber: String, threePowerIndex: Int, isMetric: Boolean): String {
        val sb = StringBuilder(formattedNumber.length + 4)
        sb.append(formattedNumber)
        val unitsToUse = "B${if (isMetric) "k" else "K"}MGTPE"
        sb.append(unitsToUse[threePowerIndex])
        if (threePowerIndex > 0)
            if (isMetric) sb.append('B') else sb.append("iB")
        return sb.toString()
    }

    override fun onFormatLong(valueToFormat: Long, unitPowerIndex: Int, isMetric: Boolean): String {
        return formatByUnit(String.format("%,d", valueToFormat), unitPowerIndex, isMetric)
    }

    override fun onFormatDouble(valueToFormat: Double, unitPowerIndex: Int, isMetric: Boolean): String {
        //alternative for using numberFormat :
        //val formattedNumber = String.format("%,.2f", valueToFormat).let { initialFormattedString ->
        //    if (initialFormattedString.contains('.'))
        //        return@let initialFormattedString.dropLastWhile { it == '0' }
        //    else return@let initialFormattedString
        //}
        return formatByUnit(numberFormat.format(valueToFormat), unitPowerIndex, isMetric)
    }
}
Log.d("AppLog", "formatting of $bytesToFormat bytes (${String.format("%,d", bytesToFormat)})")
Log.d("AppLog", bytesIntoHumanReadable(bytesToFormat, bytesFormatter))
Log.d("AppLog", "Android:${android.text.format.Formatter.formatFileSize(this, bytesToFormat)}")

Usage:

android developer
  • 112,189
  • 137
  • 688
  • 1,196
  • You seem to have an off-by-one error in your for-loop. I think it should be `unitsCount` and not `unitsCount-1`. – aioobe May 05 '14 at 12:02
  • @aioobe but this means the loop can stop when i==unitsCount, which means i==6, which means "charAt" will fail... – android developer May 05 '14 at 12:30
  • `if(result – aioobe May 05 '14 at 12:54
  • @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). – android developer May 05 '14 at 13:39
  • @aioobe Correct. I will fix it. BTW, your algorithm can also provide a weird result. try giving it "999999,true" as the arguments. it will show "1000.0 kB" , so it's rounded, but when people see it, they can wonder: why can't it show 1MB , as 1000KB=1MB ... How do you think this should be handled? It's because of the String.format, but I'm not sure how it should be fixed. – android developer May 06 '14 at 11:50
  • @aioobe Maybe using this could help: http://stackoverflow.com/questions/1305827/prevent-round-off-in-string-format-2f-doublevalue-in-java ? – android developer May 06 '14 at 11:52
  • @aioobe I've also added a short way to do it in case you use Android. – android developer Aug 04 '14 at 23:10
  • @aioobe It seems this solution doesn't work for values that are too large, as Double can't handle those. I think that "E" unit is problematic (I use the 10224 bytes-per-kilo). Till then, I think it works fine. If you send it `Long.MAX_VALUE`, it won't show the correct value. What do you think? – android developer Feb 28 '22 at 19:53
  • OK I've fixed it and I've updated my answer – android developer Mar 05 '22 at 20:03
8

Byte Units allows you to do it like this:

long input1 = 1024;
long input2 = 1024 * 1024;

Assert.assertEquals("1 KiB", BinaryByteUnit.format(input1));
Assert.assertEquals("1 MiB", BinaryByteUnit.format(input2));

Assert.assertEquals("1.024 KB", DecimalByteUnit.format(input1, "#.0"));
Assert.assertEquals("1.049 MB", DecimalByteUnit.format(input2, "#.000"));

NumberFormat format = new DecimalFormat("#.#");
Assert.assertEquals("1 KiB", BinaryByteUnit.format(input1, format));
Assert.assertEquals("1 MiB", BinaryByteUnit.format(input2, format));

I have written another library called storage-units that allows you to do it like this:

String formattedUnit1 = StorageUnits.formatAsCommonUnit(input1, "#");
String formattedUnit2 = StorageUnits.formatAsCommonUnit(input2, "#");
String formattedUnit3 = StorageUnits.formatAsBinaryUnit(input1);
String formattedUnit4 = StorageUnits.formatAsBinaryUnit(input2);
String formattedUnit5 = StorageUnits.formatAsDecimalUnit(input1, "#.00", Locale.GERMAN);
String formattedUnit6 = StorageUnits.formatAsDecimalUnit(input2, "#.00", Locale.GERMAN);
String formattedUnit7 = StorageUnits.formatAsBinaryUnit(input1, format);
String formattedUnit8 = StorageUnits.formatAsBinaryUnit(input2, format);

Assert.assertEquals("1 kB", formattedUnit1);
Assert.assertEquals("1 MB", formattedUnit2);
Assert.assertEquals("1.00 KiB", formattedUnit3);
Assert.assertEquals("1.00 MiB", formattedUnit4);
Assert.assertEquals("1,02 kB", formattedUnit5);
Assert.assertEquals("1,05 MB", formattedUnit6);
Assert.assertEquals("1 KiB", formattedUnit7);
Assert.assertEquals("1 MiB", formattedUnit8);

In case you want to force a certain unit, do this:

String formattedUnit9 = StorageUnits.formatAsKibibyte(input2);
String formattedUnit10 = StorageUnits.formatAsCommonMegabyte(input2);

Assert.assertEquals("1024.00 KiB", formattedUnit9);
Assert.assertEquals("1.00 MB", formattedUnit10);
7

Kotlin Version via Extension Property

If you are using kotlin, it's pretty easy to format file size by these extension properties. It is loop-free and completely based on pure math.


HumanizeUtils.kt

import java.io.File
import kotlin.math.log2
import kotlin.math.pow

/**
 * @author aminography
 */

val File.formatSize: String
    get() = length().formatAsFileSize

val Int.formatAsFileSize: String
    get() = toLong().formatAsFileSize

val Long.formatAsFileSize: String
    get() = log2(if (this != 0L) toDouble() else 1.0).toInt().div(10).let {
        val precision = when (it) {
            0 -> 0; 1 -> 1; else -> 2
        }
        val prefix = arrayOf("", "K", "M", "G", "T", "P", "E", "Z", "Y")
        String.format("%.${precision}f ${prefix[it]}B", toDouble() / 2.0.pow(it * 10.0))
    }

Usage:

println("0:          " + 0.formatAsFileSize)
println("170:        " + 170.formatAsFileSize)
println("14356:      " + 14356.formatAsFileSize)
println("968542985:  " + 968542985.formatAsFileSize)
println("8729842496: " + 8729842496.formatAsFileSize)

println("file: " + file.formatSize)

Result:

0:          0 B
170:        170 B
14356:      14.0 KB
968542985:  923.67 MB
8729842496: 8.13 GB

file: 6.15 MB
aminography
  • 20,387
  • 13
  • 62
  • 71
6
    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 "???";
    }
XXX
  • 8,870
  • 7
  • 43
  • 53
5

org.springframework.util.unit.DataSize could suit this requirement at least for the calculation. Then a simple decorator will do.

Peter Mortensen
  • 30,030
  • 21
  • 100
  • 124
Tama
  • 370
  • 6
  • 10
  • My requirement was to print the memory of the system and this helped me as I know it needs to be printed in MB always. – Pavan Kumar Aug 24 '20 at 06:20
4

There is now one library available that contains unit formatting. I added it to the triava library, as the only other existing library seems to be one for Android.

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
  • 452
  • 1
  • 4
  • 11
3

Create an interface:

public interface IUnits {
    public String format(long size, String pattern);
    public long getUnitSize();
}

Create the StorageUnits class:

import java.text.DecimalFormat;

public class StorageUnits {

    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;

    enum Unit implements IUnits {

        TERA_BYTE {
            @Override
            public String format(long size, String pattern) {
                return format(size, getUnitSize(), "TB", pattern);
            }
            @Override
            public long getUnitSize() {
                return T;
            }
            @Override
            public String toString() {
                return "Terabytes";
            }
        },
        GIGA_BYTE {
            @Override
            public String format(long size, String pattern) {
                return format(size, getUnitSize(), "GB", pattern);
            }
            @Override
            public long getUnitSize() {
                return G;
            }
            @Override
            public String toString() {
                return "Gigabytes";
            }
        },
        MEGA_BYTE {
            @Override
            public String format(long size, String pattern) {
                return format(size, getUnitSize(), "MB", pattern);
            }
            @Override
            public long getUnitSize() {
                return M;
            }
            @Override
            public String toString() {
                return "Megabytes";
            }
        },
        KILO_BYTE {
            @Override
            public String format(long size, String pattern) {
                return format(size, getUnitSize(), "kB", pattern);
            }
            @Override
            public long getUnitSize() {
                return K;
            }
            @Override
            public String toString() {
                return "Kilobytes";
            }

        };

        String format(long size, long base, String unit, String pattern) {
            return new DecimalFormat(pattern).format(
                           Long.valueOf(size).doubleValue() /
                           Long.valueOf(base).doubleValue()
            ) + unit;
        }
    }

    public static String format(long size, String pattern) {
        for(Unit unit : Unit.values()) {
            if(size >= unit.getUnitSize()) {
                return unit.format(size, pattern);
            }
        }
        return ("???(" + size + ")???");
    }

    public static String format(long size) {
        return format(size, "#,##0.#");
    }
}

Call it:

class Main {
    public static void main(String... args) {
        System.out.println(StorageUnits.format(21885));
        System.out.println(StorageUnits.format(2188121545L));
    }
}

Output:

21.4kB
2GB
Peter Mortensen
  • 30,030
  • 21
  • 100
  • 124
Ahmad AlMughrabi
  • 1,224
  • 12
  • 27
3

Yet another concise solution without loop but with locale-sensitive formatting and correct binary prefixes:

import java.util.Locale;

public final class Bytes {

  private Bytes() {
  }

  public static String format(long value, Locale locale) {
    if (value < 1024) {
      return value + " B";
    }
    int z = (63 - Long.numberOfLeadingZeros(value)) / 10;
    return String.format(locale, "%.1f %siB", (double) value / (1L << (z * 10)), " KMGTPE".charAt(z));
  }
}

Test:

Locale locale = Locale.getDefault()
System.out.println(Bytes.format(1L, locale))
System.out.println(Bytes.format(2L * 1024, locale))
System.out.println(Bytes.format(3L * 1024 * 1024, locale))
System.out.println(Bytes.format(4L * 1024 * 1024 * 1024, locale))
System.out.println(Bytes.format(5L * 1024 * 1024 * 1024 * 1024, locale))
System.out.println(Bytes.format(6L * 1024 * 1024 * 1024 * 1024 * 1024, locale))
System.out.println(Bytes.format(Long.MAX_VALUE, locale))

Output:

1 B
2.0 KiB
3.0 MiB
4.0 GiB
5.0 GiB
6.0 PiB
8.0 EiB
Michel Jung
  • 2,568
  • 4
  • 28
  • 44
2
String[] fileSizeUnits = {"bytes", "KB", "MB", "GB", "TB", "PB", "EB", "ZB", "YB"};

public String calculateProperFileSize(double bytes){
    String sizeToReturn = "";
    int index = 0;
    for(index = 0; index < fileSizeUnits.length; index++){
        if(bytes < 1024){
            break;
        }
        bytes = bytes / 1024;
    }

    System.out.println("File size in proper format: " + bytes + " " + fileSizeUnits[index]);
    sizeToReturn = String.valueOf(bytes) + " " + fileSizeUnits[index];
    return sizeToReturn;
}

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

Vishwajit R. Shinde
  • 467
  • 2
  • 5
  • 18
2

You can use StringUtils’s TraditionalBinarPrefix:

public static String humanReadableInt(long number) {
    return TraditionalBinaryPrefix.long2String(number, ””, 1);
}
Peter Mortensen
  • 30,030
  • 21
  • 100
  • 124
Joe
  • 2,188
  • 1
  • 21
  • 32
2

Here's a Go version. For simplicity, I've only included the binary output case.

func sizeOf(bytes int64) string {
    const unit = 1024
    if bytes < unit {
        return fmt.Sprintf("%d B", bytes)
    }

    fb := float64(bytes)
    exp := int(math.Log(fb) / math.Log(unit))
    pre := "KMGTPE"[exp-1]
    div := math.Pow(unit, float64(exp))
    return fmt.Sprintf("%.1f %ciB", fb / div, pre)
}
Peter Mortensen
  • 30,030
  • 21
  • 100
  • 124
Rick-777
  • 9,034
  • 5
  • 33
  • 49
2

I'm using slighly modified method than accepted answer :

public static String formatFileSize(long bytes) {
        if (bytes <= 0) return "";
        if (bytes < 1000) return bytes + " B";
        CharacterIterator ci = new StringCharacterIterator("kMGTPE");
        while (bytes >= 99_999) {
            bytes /= 1000;
            ci.next();
        }
        return String.format(Locale.getDefault(), "%.1f %cB", bytes / 1000.0, ci.current());
    }

Because i want to see another output :

                              SI   

                   0:            <--------- instead of 0 B
                  27:       27 B     
                 999:      999 B   
                1000:     1.0 kB   
                1023:     1.0 kB   
                1024:     1.0 kB 
                1728:     1.7 kB   
              110592:     0.1 MB <--------- instead of 110.6 kB
             7077888:     7.1 MB  
           452984832:     0.5 GB <--------- instead of 453.0 MB
         28991029248:    29.0 GB  
i30mb1
  • 2,952
  • 2
  • 14
  • 31
2

For kotlin lover use this extension

fun Long.readableFormat(): String {
    if (this <= 0 ) return "0"
    val units = arrayOf("B", "kB", "MB", "GB", "TB")
    val digitGroups = (log10(this.toDouble()) / log10(1024.0)).toInt()
    return DecimalFormat("#,##0.#").format(this / 1024.0.pow(digitGroups.toDouble())).toString() + " " + units[digitGroups]
}

Now use

val size : Long = 90836457
val readbleString = size.readableFormat()

Another approach

val Long.formatSize : String
    get() {
        if (this <= 0) return "0"
        val units = arrayOf("B", "kB", "MB", "GB", "TB")
        val digitGroups = (log10(this.toDouble()) / log10(1024.0)).toInt()
        return DecimalFormat("#,##0.#").format(this / 1024.0.pow(digitGroups.toDouble())).toString() + " " + units[digitGroups]
    }

Now use

val size : Long = 90836457
val readbleString = size.formatSize 
Tarif Chakder
  • 1,381
  • 9
  • 10
1

Here's the C# .NET equivalent for Java correct consensus answer above (there's another below which has shorter code):

    public static String BytesNumberToHumanReadableString(long bytes, bool SI1000orBinary1024)
    {
        int unit = SI1000orBinary1024 ? 1000 : 1024;
        if (bytes < unit)
            return bytes + " B";

        int exp = (int)(Math.Log(bytes) / Math.Log(unit));
        String pre = (SI1000orBinary1024 ? "kMGTPE" : "KMGTPE")[(exp - 1)] + (SI1000orBinary1024 ? "" : "i");
        return String.Format("{0:F1} {1}B", bytes / Math.Pow(unit, exp), pre);
    }

Technically speaking, if we stick to SI units, this routine works for any regular use of numbers. There are many other good answers from experts. Suppose you are doing databinding of numbers on gridviews, it's worth to check out performance optimized routines from them.

PS: This was posted because this question/answer came up on top on a Google search while I was doing a C# project.

Peter Mortensen
  • 30,030
  • 21
  • 100
  • 124
1

Maybe you can use this code (in C#):

long Kb = 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 size.ToString() + " byte";

if (size < Mb)  return (size / Kb).ToString("###.##") + " Kb.";
if (size < Gb)  return (size / Mb).ToString("###.##") + " Mb.";
if (size < Tb)  return (size / Gb).ToString("###.##") + " Gb.";
if (size < Pb)  return (size / Tb).ToString("###.##") + " Tb.";
if (size < Eb)  return (size / Pb).ToString("###.##") + " Pb.";
if (size >= Eb) return (size / Eb).ToString("###.##") + " Eb.";

return "invalid size";
Peter Mortensen
  • 30,030
  • 21
  • 100
  • 124
1

Here is the conversion from aioobe converted to Kotlin:

/**
 * https://stackoverflow.com/a/3758880/1006741
 */
fun Long.humanReadableByteCountBinary(): String {
    val b = when (this) {
        Long.MIN_VALUE -> Long.MAX_VALUE
        else -> abs(this)
    }
    return when {
        b < 1024L -> "$this B"
        b <= 0xfffccccccccccccL shr 40 -> "%.1f KiB".format(Locale.UK, this / 1024.0)
        b <= 0xfffccccccccccccL shr 30 -> "%.1f MiB".format(Locale.UK, this / 1048576.0)
        b <= 0xfffccccccccccccL shr 20 -> "%.1f GiB".format(Locale.UK, this / 1.073741824E9)
        b <= 0xfffccccccccccccL shr 10 -> "%.1f TiB".format(Locale.UK, this / 1.099511627776E12)
        b <= 0xfffccccccccccccL -> "%.1f PiB".format(Locale.UK, (this shr 10) / 1.099511627776E12)
        else -> "%.1f EiB".format(Locale.UK, (this shr 20) / 1.099511627776E12)
    }
}
Peter Mortensen
  • 30,030
  • 21
  • 100
  • 124
Kibotu
  • 73
  • 8
0

Try JSR 363. Its unit extension modules like Unicode CLDR (in GitHub: uom-systems) do all that for you.

You can use MetricPrefix included in every implementation or BinaryPrefix (comparable to some of the examples above) and if you e.g. live and work in India or a nearby country, IndianPrefix (also in the common module of uom-systems) allows you to use and format "Crore Bytes" or "Lakh Bytes", too.

Peter Mortensen
  • 30,030
  • 21
  • 100
  • 124
Werner Keil
  • 550
  • 5
  • 11
0
public String humanReadable(long size) {
    long limit = 10 * 1024;
    long limit2 = limit * 2 - 1;
    String negative = "";
    if(size < 0) {
        negative = "-";
        size = Math.abs(size);
    }

    if(size < limit) {
        return String.format("%s%s bytes", negative, size);
    } else {
        size = Math.round((double) size / 1024);
        if (size < limit2) {
            return String.format("%s%s kB", negative, size);
        } else {
            size = Math.round((double)size / 1024);
            if (size < limit2) {
                return String.format("%s%s MB", negative, size);
            } else {
                size = Math.round((double)size / 1024);
                if (size < limit2) {
                    return String.format("%s%s GB", negative, size);
                } else {
                    size = Math.round((double)size / 1024);
                        return String.format("%s%s TB", negative, size);
                }
            }
        }
    }
}
Samkov Max
  • 21
  • 1
0

Use the following function to get exact information. It is generated by taking the base of the ATM_CashWithdrawl concept.

getFullMemoryUnit(): Total: [123 MB], Max: [1 GB, 773 MB, 512 KB], Free: [120 MB, 409 KB, 304 Bytes]
public static String getFullMemoryUnit(long unit) {
    long BYTE = 1024, KB = BYTE, MB = KB * KB, GB = MB * KB, TB = GB * KB;
    long KILO_BYTE, MEGA_BYTE = 0, GIGA_BYTE = 0, TERA_BYTE = 0;
    unit = Math.abs(unit);
    StringBuffer buffer = new StringBuffer();
    if ( unit / TB > 0 ) {
        TERA_BYTE = (int) (unit / TB);
        buffer.append(TERA_BYTE+" TB");
        unit -= TERA_BYTE * TB;
    }
    if ( unit / GB > 0 ) {
        GIGA_BYTE = (int) (unit / GB);
        if (TERA_BYTE != 0) buffer.append(", ");
        buffer.append(GIGA_BYTE+" GB");
        unit %= GB;
    }
    if ( unit / MB > 0 ) {
        MEGA_BYTE = (int) (unit / MB);
        if (GIGA_BYTE != 0) buffer.append(", ");
        buffer.append(MEGA_BYTE+" MB");
        unit %= MB;
    }
    if ( unit / KB > 0 ) {
        KILO_BYTE = (int) (unit / KB);
        if (MEGA_BYTE != 0) buffer.append(", ");
        buffer.append(KILO_BYTE+" KB");
        unit %= KB;
    }
    if ( unit > 0 ) buffer.append(", "+unit+" Bytes");
    return buffer.toString();
}

I have just modified the code of facebookarchive-StringUtils to get the below format. The same format you will get when you use apache.hadoop-StringUtils

getMemoryUnit(): Total: [123.0 MB], Max: [1.8 GB], Free: [120.4 MB]
public static String getMemoryUnit(long bytes) {
    DecimalFormat oneDecimal = new DecimalFormat("0.0");
    float BYTE = 1024.0f, KB = BYTE, MB = KB * KB, GB = MB * KB, TB = GB * KB;
    long absNumber = Math.abs(bytes);
    double result = bytes;
    String suffix = " Bytes";
    if (absNumber < MB) {
        result = bytes / KB;
        suffix = " KB";
    } else if (absNumber < GB) {
        result = bytes / MB;
        suffix = " MB";
    } else if (absNumber < TB) {
        result = bytes / GB;
        suffix = " GB";
    }
    return oneDecimal.format(result) + suffix;
}

Example usage of the above methods:

public static void main(String[] args) {
    Runtime runtime = Runtime.getRuntime();
    int availableProcessors = runtime.availableProcessors();

    long heapSize = Runtime.getRuntime().totalMemory();
    long heapMaxSize = Runtime.getRuntime().maxMemory();
    long heapFreeSize = Runtime.getRuntime().freeMemory();

    System.out.format("Total: [%s], Max: [%s], Free: [%s]\n", heapSize, heapMaxSize, heapFreeSize);
    System.out.format("getMemoryUnit(): Total: [%s], Max: [%s], Free: [%s]\n",
            getMemoryUnit(heapSize), getMemoryUnit(heapMaxSize), getMemoryUnit(heapFreeSize));
    System.out.format("getFullMemoryUnit(): Total: [%s], Max: [%s], Free: [%s]\n",
            getFullMemoryUnit(heapSize), getFullMemoryUnit(heapMaxSize), getFullMemoryUnit(heapFreeSize));
}

Bytes to get the above format

Total: [128974848], Max: [1884815360], Free: [126248240]

In order to display time in a human-readable format, use the function millisToShortDHMS(long duration).

Peter Mortensen
  • 30,030
  • 21
  • 100
  • 124
Yash
  • 8,518
  • 2
  • 64
  • 71
0

I usually do it in this way, what do you think?

public static String getFileSize(double size) {
    return _getFileSize(size,0,1024);
}

public static String _getFileSize(double size, int i, double base) {
    String units = " KMGTP";
    String unit = (i>0)?(""+units.charAt(i)).toUpperCase()+"i":"";
    if(size<base)
        return size +" "+unit.trim()+"B";
    else {
        size = Math.floor(size/base);
        return _getFileSize(size,++i,base);
    }
}
neo7bf
  • 141
  • 7
0

Below is a fast, simple and readable code snippet to achieve this:

/**
 * Converts byte size to human readable strings (also declares useful constants)
 *
 * @see <a href="https://en.wikipedia.org/wiki/File_size">File size</a>
 */
@SuppressWarnings("SpellCheckingInspection")
public class HumanReadableSize {
    public static final double
            KILO = 1000L, // 1000 power 1 (10 power 3)
            KIBI = 1024L, // 1024 power 1 (2 power 10)
            MEGA = KILO * KILO, // 1000 power 2 (10 power 6)
            MEBI = KIBI * KIBI, // 1024 power 2 (2 power 20)
            GIGA = MEGA * KILO, // 1000 power 3 (10 power 9)
            GIBI = MEBI * KIBI, // 1024 power 3 (2 power 30)
            TERA = GIGA * KILO, // 1000 power 4 (10 power 12)
            TEBI = GIBI * KIBI, // 1024 power 4 (2 power 40)
            PETA = TERA * KILO, // 1000 power 5 (10 power 15)
            PEBI = TEBI * KIBI, // 1024 power 5 (2 power 50)
            EXA = PETA * KILO, // 1000 power 6 (10 power 18)
            EXBI = PEBI * KIBI; // 1024 power 6 (2 power 60)

    private static final DecimalFormat df = new DecimalFormat("#.##");

    public static String binaryBased(long size) {
        if (size < 0) {
            throw new IllegalArgumentException("Argument cannot be negative");
        } else if (size < KIBI) {
            return df.format(size).concat("B");
        } else if (size < MEBI) {
            return df.format(size / KIBI).concat("KiB");
        } else if (size < GIBI) {
            return df.format(size / MEBI).concat("MiB");
        } else if (size < TEBI) {
            return df.format(size / GIBI).concat("GiB");
        } else if (size < PEBI) {
            return df.format(size / TEBI).concat("TiB");
        } else if (size < EXBI) {
            return df.format(size / PEBI).concat("PiB");
        } else {
            return df.format(size / EXBI).concat("EiB");
        }
    }

    public static String decimalBased(long size) {
        if (size < 0) {
            throw new IllegalArgumentException("Argument cannot be negative");
        } else if (size < KILO) {
            return df.format(size).concat("B");
        } else if (size < MEGA) {
            return df.format(size / KILO).concat("KB");
        } else if (size < GIGA) {
            return df.format(size / MEGA).concat("MB");
        } else if (size < TERA) {
            return df.format(size / GIGA).concat("GB");
        } else if (size < PETA) {
            return df.format(size / TERA).concat("TB");
        } else if (size < EXA) {
            return df.format(size / PETA).concat("PB");
        } else {
            return df.format(size / EXA).concat("EB");
        }
    }
}

Note:

  1. Above code is verbose and straightforward.
    • It does not use loops (loops should be used only when you do not know how many times you need to iterate during compilation time)
    • It does not make unnecessary library calls (StringBuilder, Math etc.)
  2. Above code is fast and uses very less memory. Based on benchmarks run on my personal entry-level cloud machine, it's the fastest (not that performance matters in these cases, but still)
  3. Above code is a modified version of one of the good answers
Manu Manjunath
  • 5,961
  • 2
  • 31
  • 31
-1
filename=filedilg.getSelectedFile().getAbsolutePath();
File file=new File(filename);

String disp=FileUtils.byteCountToDisplaySize(file.length());
System.out.println("THE FILE PATH IS "+file+"THIS File SIZE IS IN MB "+disp);
benka
  • 4,702
  • 35
  • 46
  • 58
Mano Chella
  • 191
  • 1
  • 3
  • 1
    This answer, while it works, is a complement to a previous answer in this thread by @user601806: https://stackoverflow.com/a/4888400/3987745 For this answer to work, you need Apache Commons IO (http://commons.apache.org/proper/commons-io/) dependency. – Edward Quixote Jan 11 '20 at 10:26