Search code examples
javafilesize

java get file size efficiently


While googling, I see that using java.io.File#length() can be slow. FileChannel has a size() method that is available as well.

Is there an efficient way in java to get the file size?


Solution

  • Well, I tried to measure it up with the code below:

    For runs = 1 and iterations = 1 the URL method is fastest most times followed by channel. I run this with some pause fresh about 10 times. So for one time access, using the URL is the fastest way I can think of:

    LENGTH sum: 10626, per Iteration: 10626.0
    
    CHANNEL sum: 5535, per Iteration: 5535.0
    
    URL sum: 660, per Iteration: 660.0
    

    For runs = 5 and iterations = 50 the picture draws different.

    LENGTH sum: 39496, per Iteration: 157.984
    
    CHANNEL sum: 74261, per Iteration: 297.044
    
    URL sum: 95534, per Iteration: 382.136
    

    File must be caching the calls to the filesystem, while channels and URL have some overhead.

    Code:

    import java.io.*;
    import java.net.*;
    import java.util.*;
    
    public enum FileSizeBench {
    
        LENGTH {
            @Override
            public long getResult() throws Exception {
                File me = new File(FileSizeBench.class.getResource(
                        "FileSizeBench.class").getFile());
                return me.length();
            }
        },
        CHANNEL {
            @Override
            public long getResult() throws Exception {
                FileInputStream fis = null;
                try {
                    File me = new File(FileSizeBench.class.getResource(
                            "FileSizeBench.class").getFile());
                    fis = new FileInputStream(me);
                    return fis.getChannel().size();
                } finally {
                    fis.close();
                }
            }
        },
        URL {
            @Override
            public long getResult() throws Exception {
                InputStream stream = null;
                try {
                    URL url = FileSizeBench.class
                            .getResource("FileSizeBench.class");
                    stream = url.openStream();
                    return stream.available();
                } finally {
                    stream.close();
                }
            }
        };
    
        public abstract long getResult() throws Exception;
    
        public static void main(String[] args) throws Exception {
            int runs = 5;
            int iterations = 50;
    
            EnumMap<FileSizeBench, Long> durations = new EnumMap<FileSizeBench, Long>(FileSizeBench.class);
    
            for (int i = 0; i < runs; i++) {
                for (FileSizeBench test : values()) {
                    if (!durations.containsKey(test)) {
                        durations.put(test, 0l);
                    }
                    long duration = testNow(test, iterations);
                    durations.put(test, durations.get(test) + duration);
                    // System.out.println(test + " took: " + duration + ", per iteration: " + ((double)duration / (double)iterations));
                }
            }
    
            for (Map.Entry<FileSizeBench, Long> entry : durations.entrySet()) {
                System.out.println();
                System.out.println(entry.getKey() + " sum: " + entry.getValue() + ", per Iteration: " + ((double)entry.getValue() / (double)(runs * iterations)));
            }
    
        }
    
        private static long testNow(FileSizeBench test, int iterations)
                throws Exception {
            long result = -1;
            long before = System.nanoTime();
            for (int i = 0; i < iterations; i++) {
                if (result == -1) {
                    result = test.getResult();
                    //System.out.println(result);
                } else if ((result = test.getResult()) != result) {
                     throw new Exception("variance detected!");
                 }
            }
            return (System.nanoTime() - before) / 1000;
        }
    
    }