0

I'd like to print file/directory sizes in Java, however for files larger than 1GB I cannot. For example, when I check a file with ~1.3 GB it writes 0.000 TB, this is shown on the debugging screenshot. The if-else jumps to the else branch. Probably the maximum limit of long type? Please advice me, the code is the following:

long size;
String notation;
if (file.isDirectory()) {
    // File is a directory, calculate size of all files in the directory
    size = 0;
    for (File f : file.listFiles()) {
        size += f.length();
    }
} else {
    // File is a regular file, use size of file
    size = file.length();
}

// Conversion
long bytes = size;
long kilobytes = (bytes / 1024);
long megabytes = (kilobytes / 1024);
long gigabytes = (megabytes / 1024);
long terabytes = (gigabytes / 1024);
long petabytes = (terabytes / 1024);
long exabytes = (petabytes / 1024);
//long zettabytes = (exabytes / 1024);
//long yottabytes = (zettabytes / 1024);

if (size > 0 && size < kilobytes){
    notation = "B";
    System.out.println(size+notation);
} else if (size > kilobytes && size < megabytes) {
    // file is smaller than 1 MB, return size in KB
    size /= 1024;
    notation = "KB";
    System.out.println(size+notation);
} else if (size > megabytes && size < gigabytes) {
    // file is smaller than 1 GB, return size in MB
    notation = "MB";
    size /= 1024.0 * 1024;
    System.out.println(size+notation);
} else if (size > gigabytes && size < terabytes) {
    // file is larger than 1 GB, return size in GB
    notation = "GB";
    size /= 1024.0 * 1024.0 * 1024.0;
    System.out.println(size+notation);
} else {
    // file is larger than 1 TB, return size in TB
    notation = "TB";
    size /= 1024.0 * 1024.0 * 1024.0 * 1024;
    System.out.println(size+notation);
}

// cast size to double before passing it to String.format
return String.format("[Size: %.3f %s]", (double) size, notation);

}

Debugging shows the following: screenshot

EDIT: I have changed to BigDecimal, the values seems correct, but still jumps to TB. Please see the screenshot: screenshot 2

SOLUTION: Now everything is perfect, thank you for all ;)

if (bsize.compareTo(BigDecimal.valueOf(1024)) < 0) {
    notation = "B";
    System.out.println(bsize+notation);
} else if (bsize.compareTo(BigDecimal.valueOf(1024*1024)) < 0) {
    // file is smaller than 1 MB, return size in KB
    bsize = bsize.divide(BigDecimal.valueOf(1024));
    notation = "KB";
    System.out.println(bsize+notation);
} else if (bsize.compareTo(BigDecimal.valueOf(1024L*1024L*1024L)) < 0) {
    // file is smaller than 1 GB, return size in MB
    notation = "MB";
    bsize = bsize.divide(BigDecimal.valueOf(1024*1024));
    System.out.println(bsize+notation);
} else if (bsize.compareTo(BigDecimal.valueOf(1024L*1024L*1024L*1024L)) < 0) {
    // file is larger than 1 GB, return size in GB
    notation = "GB";
    System.out.println(bsize+notation);
    bsize = bsize.divide(BigDecimal.valueOf(1024*1024*1024));
    System.out.println(bsize+notation);
} else {
    // file is larger than 1 TB, return size in TB
    notation = "TB";
    bsize = bsize.divide(BigDecimal.valueOf(1024L*1024L*1024L*1024L));
    System.out.println(bsize+notation);
}
Thend
  • 95
  • 7
  • What do you mean you can't? What result do you expect and what do you get, instead? – Federico klez Culloca Jan 05 '23 at 09:06
  • Anyway, if you mean you're overflowing, try using `BigDecimal` if you care about decimals or `BigInteger` if you only care about integers. – Federico klez Culloca Jan 05 '23 at 09:08
  • @FedericoklezCulloca Sorry for my quick and lazy posting, I edited the post (early morning here). The problem is that for files larger than 1Gb it directly jumps to TB and shows zero. – Thend Jan 05 '23 at 09:11
  • 1
    Of course it does. `size` can't be less than `size / n` if `n < size` so none of the previous conditions (`size < kilobytes`, `size < megabytes` etc) will ever be true. And then it shows 0 because you're reassigning the value back to size, which is a `long` and doesn't have decimals. – Federico klez Culloca Jan 05 '23 at 09:20
  • You could avoid all those `&& size < xxx` in your condition if you reverse the order of the `if`s (i.e., start with TB, then GB etc...) – Federico klez Culloca Jan 05 '23 at 09:21
  • @FedericoklezCulloca I changed to BigDecimal, however still jumps to TB, what is your suggestion? Should I change the relations somehow, not clear how. (Edited the post!) – Thend Jan 05 '23 at 09:44
  • I suggested to change to `BigDecimal` **if** the problem was overflowing (which is not, as you then explained). See my other comments that explain what the actual problems are and how to fix this. – Federico klez Culloca Jan 05 '23 at 09:46
  • 1
    I forgot, the solution to not seeing 0 is to not reassign to `size`. Either assign the result to a `double` or just print `size / (1024.0 * 1024.0 *1024.0 *1024)` directly. – Federico klez Culloca Jan 05 '23 at 09:49
  • 1
    Does this answer your question? [How can I convert byte size into a human-readable format in Java?](https://stackoverflow.com/questions/3758606/how-can-i-convert-byte-size-into-a-human-readable-format-in-java) – Eritrean Jan 05 '23 at 10:02
  • @FedericoklezCulloca I have changed size / (1024.0 * 1024.0 *1024.0 *1024) as you mentioned, for all of the code, now works perfectly. I edited the post with the correct code. Best! – Thend Jan 05 '23 at 10:27
  • 1
    @Thend glad I could help :) It would be better if you posted your solution as an actual answer, rather than an edit to your original question. It makes everything more clear **and** helps future readers which may have a similar problem to yours find a solution. – Federico klez Culloca Jan 05 '23 at 10:37

0 Answers0