Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

File.length() returning incorrect value in Java

Tags:

java

file

When calling .length() on a file object, files over 2 GB return an incorrect value.

This is happening in a web application running in a tomcat container.

For example, a file that windows reports as 2,083,344,714 bytes is coming back as 1887961088 from java.

Here are the environmental details:

  • jdk 1.6.0_24(64 bit)
  • Java JotSpot(TM) 64-Bit Server VM (build 17.0-b17, mixed mode)
  • Tomcat 6.0.29
  • Windows Server 2008 r2

So I immediately suspected something to do with a 32bit VM, but everything appears to be running in 64 bit. I'm totally stumped, any help would be greatly appreciated, if only help developing some tests to see if the problem is related to something running in 32 mode somehow..

EDIT:

To answer some comments: When I run a really simple test case using the same JVM (just output file.length) I get the correct value: 2,083,344,714.

I am pretty confident that this should work, I am just feeling like something about my tomcat configuration/ java configuration/ application is giving me a hard time. The fact that it is affecting only files over a certain size really makes it seem like an issue with 32 bit vs 64 bit, but as far as I can tell everything is 64 bit.

EDIT 2: Starting to suspect this is pretty much not possible, and I might have an issue with a thread taking the length of a file before it has been copied completely. I'll post here when I figure it out, if anyone cares :-)

like image 939
eric Avatar asked Oct 11 '12 23:10

eric


People also ask

What does file length return?

length() returns the length of the file defined by this abstract pathname. The return value is unspecified if this pathname defines a directory.

What will the length method in the File class return?

The length() function is a part of File class in Java . This function returns the length of the file denoted by the this abstract pathname was length. The function returns long value which represents the number of bytes else returns 0L if the file does not exists or if an exception occurs.


1 Answers

Seems to work fine for me...

pagefile.sys on Windows 7 x64, reported by DOS as 8446545920 bytes

Java 7.0_02 x32 8446545920 / 7.87 gb

Java 1.6_30 x32 8446545920 / 7.87 gb

import java.io.File;
import java.text.NumberFormat;

public class TestFileSize {

    public static void main(String[] args) {
        File test1 = new File("C:/pagefile.sys");
        File test2 = new File("C:/hiberfil.sys");

        System.out.println(test1.length() + " / " + ByteFormatter.format(test1.length()));
        System.out.println(test2.length() + " / " + ByteFormatter.format(test2.length()));

    }

    public static class ByteFormatter {

        public static final long KILO_BYTES = 1024;
        public static final long MEGA_BYTES = 1024 * KILO_BYTES;
        public static final long GIGA_BYTES = 1024 * MEGA_BYTES;
        public static final long TERA_BYTES = 1024 * GIGA_BYTES;
        public enum Format {

            TeraBytes(TERA_BYTES),
            GigaBytes(GIGA_BYTES),
            MegaBytes(MEGA_BYTES),
            KiloBytes(KILO_BYTES);
            private long multiplier;

            private Format(long multiplier) {
                this.multiplier = multiplier;
            }

            public long getMultiplier() {
                return multiplier;
            }
        }

        public static String format(long bytes) {
            NumberFormat nf = NumberFormat.getNumberInstance();
            nf.setMaximumFractionDigits(2);
            nf.setMinimumFractionDigits(0);
            String format = bytes + " bytes";
            if (bytes / TERA_BYTES > 0) {
                format = nf.format((double) bytes / TERA_BYTES) + " tb";
            } else if (bytes / GIGA_BYTES > 0) {
                format = nf.format((double) bytes / GIGA_BYTES) + " gb";
            } else if (bytes / MEGA_BYTES > 0) {
                format = nf.format((double) bytes / MEGA_BYTES) + " mb";
            } else if (bytes / KILO_BYTES > 0) {
                format = nf.format((double) bytes / KILO_BYTES) + " kb";
            } else {
                format = nf.format(bytes) + " bytes";
            }

            return format;
        }

        public static String formatMegaBytes(long lMegaBytes) {

            return format((long) ((double) lMegaBytes * MEGA_BYTES));

        }

        public static String formatKiloBytes(long kbytes) {

            return format(kbytes * KILO_BYTES);

        }

        public static String formatGigaBytes(long gbytes) {

            return format(gbytes * GIGA_BYTES);

        }

        public static String formatTeraBytes(long gbytes) {

            return format(gbytes * TERA_BYTES);

        }

        public static long toBytes(String value, Format format) {

            long multipler = format.getMultiplier();

            long bytes = (long) (Double.parseDouble(value.trim()) * multipler);

            return bytes;

        }

        public static long toBytes(String sValue) {

            long lBytes = 0;

            if (sValue.indexOf(" ") > -1) {

                String sElements[] = sValue.split(" ");

                lBytes = Long.parseLong(sElements[0]);

                if (sElements[1].toLowerCase().startsWith("gb")) {

                    lBytes *= GIGA_BYTES;

                } else if (sElements[1].toLowerCase().startsWith("mb")) {

                    lBytes *= MEGA_BYTES;

                } else if (sElements[1].toLowerCase().startsWith("kb")) {

                    lBytes *= KILO_BYTES;

                }

            } else {

                sValue = sValue.trim();
                long lMultiplier = 1;
                String sBytes = null;

                if (sValue.toLowerCase().endsWith("gb")) {

                    sBytes = sValue.substring(0, sValue.toLowerCase().indexOf("gb"));
                    lMultiplier = GIGA_BYTES;

                } else if (sValue.toLowerCase().endsWith("mb")) {

                    sBytes = sValue.substring(0, sValue.toLowerCase().indexOf("mb"));
                    lMultiplier = MEGA_BYTES;

                } else if (sValue.toLowerCase().endsWith("kb")) {

                    sBytes = sValue.substring(0, sValue.toLowerCase().indexOf("kb"));
                    lMultiplier = KILO_BYTES;

                }

                lBytes = Long.parseLong(sBytes);

                lBytes *= lMultiplier;

            }

            return lBytes;

        }
    }
}
like image 101
MadProgrammer Avatar answered Oct 26 '22 23:10

MadProgrammer