Get size of folder or file

2019-01-01 15:28发布

How can I retrieve size of folder or file in Java?

14条回答
零度萤火
2楼-- · 2019-01-01 15:40

Using java-7 nio api, calculating the folder size can be done a lot quicker.

Here is a ready to run example that is robust and won't throw an exception. It will log directories it can't enter or had trouble traversing. Symlinks are ignored, and concurrent modification of the directory won't cause more trouble than necessary.

/**
 * Attempts to calculate the size of a file or directory.
 * 
 * <p>
 * Since the operation is non-atomic, the returned value may be inaccurate.
 * However, this method is quick and does its best.
 */
public static long size(Path path) {

    final AtomicLong size = new AtomicLong(0);

    try {
        Files.walkFileTree(path, new SimpleFileVisitor<Path>() {
            @Override
            public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) {

                size.addAndGet(attrs.size());
                return FileVisitResult.CONTINUE;
            }

            @Override
            public FileVisitResult visitFileFailed(Path file, IOException exc) {

                System.out.println("skipped: " + file + " (" + exc + ")");
                // Skip folders that can't be traversed
                return FileVisitResult.CONTINUE;
            }

            @Override
            public FileVisitResult postVisitDirectory(Path dir, IOException exc) {

                if (exc != null)
                    System.out.println("had trouble traversing: " + dir + " (" + exc + ")");
                // Ignore errors traversing a folder
                return FileVisitResult.CONTINUE;
            }
        });
    } catch (IOException e) {
        throw new AssertionError("walkFileTree will not throw IOException if the FileVisitor does not");
    }

    return size.get();
}
查看更多
美炸的是我
3楼-- · 2019-01-01 15:42

After lot of researching and looking into different solutions proposed here at StackOverflow. I finally decided to write my own solution. My purpose is to have no-throw mechanism because I don't want to crash if the API is unable to fetch the folder size. This method is not suitable for mult-threaded scenario.

First of all I want to check for valid directories while traversing down the file system tree.

private static boolean isValidDir(File dir){
    if (dir != null && dir.exists() && dir.isDirectory()){
        return true;
    }else{
        return false;
    }
}

Second I do not want my recursive call to go into symlinks (softlinks) and include the size in total aggregate.

public static boolean isSymlink(File file) throws IOException {
    File canon;
    if (file.getParent() == null) {
        canon = file;
    } else {
        canon = new File(file.getParentFile().getCanonicalFile(),
                file.getName());
    }
    return !canon.getCanonicalFile().equals(canon.getAbsoluteFile());
}

Finally my recursion based implementation to fetch the size of the specified directory. Notice the null check for dir.listFiles(). According to javadoc there is a possibility that this method can return null.

public static long getDirSize(File dir){
    if (!isValidDir(dir))
        return 0L;
    File[] files = dir.listFiles();
    //Guard for null pointer exception on files
    if (files == null){
        return 0L;
    }else{
        long size = 0L;
        for(File file : files){
            if (file.isFile()){
                size += file.length();
            }else{
                try{
                    if (!isSymlink(file)) size += getDirSize(file);
                }catch (IOException ioe){
                    //digest exception
                }
            }
        }
        return size;
    }
}

Some cream on the cake, the API to get the size of the list Files (might be all of files and folder under root).

public static long getDirSize(List<File> files){
    long size = 0L;
    for(File file : files){
        if (file.isDirectory()){
            size += getDirSize(file);
        } else {
            size += file.length();
        }
    }
    return size;
}
查看更多
永恒的永恒
4楼-- · 2019-01-01 15:45

File.length() (Javadoc).

Note that this doesn't work for directories, or is not guaranteed to work.

For a directory, what do you want? If it's the total size of all files underneath it, you can recursively walk children using File.list() and File.isDirectory() and sum their sizes.

查看更多
孤独寂梦人
5楼-- · 2019-01-01 15:48

You need FileUtils#sizeOfDirectory(File) from commons-io.

Note that you will need to manually check whether the file is a directory as the method throws an exception if a non-directory is passed to it.

WARNING: This method (as of commons-io 2.4) has a bug and may throw IllegalArgumentException if the directory is concurrently modified.

查看更多
还给你的自由
6楼-- · 2019-01-01 15:48

If you want to use Java 8 NIO API, the following program will print the size, in bytes, of the directory it is located in.

import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;

public class PathSize {

    public static void main(String[] args) {
        Path path = Paths.get(".");
        long size = calculateSize(path);
        System.out.println(size);
    }

    /**
     * Returns the size, in bytes, of the specified <tt>path</tt>. If the given
     * path is a regular file, trivially its size is returned. Else the path is
     * a directory and its contents are recursively explored, returning the
     * total sum of all files within the directory.
     * <p>
     * If an I/O exception occurs, it is suppressed within this method and
     * <tt>0</tt> is returned as the size of the specified <tt>path</tt>.
     * 
     * @param path path whose size is to be returned
     * @return size of the specified path
     */
    public static long calculateSize(Path path) {
        try {
            if (Files.isRegularFile(path)) {
                return Files.size(path);
            }

            return Files.list(path).mapToLong(PathSize::calculateSize).sum();
        } catch (IOException e) {
            return 0L;
        }
    }

}

The calculateSize method is universal for Path objects, so it also works for files. Note that if a file or directory is inaccessible, in this case the returned size of the path object will be 0.

查看更多
查无此人
7楼-- · 2019-01-01 15:49

In Java 8:

long size = Files.walk(path).mapToLong( p -> p.toFile().length() ).sum();

It would be nicer to use Files::size in the map step but it throws a checked exception.

UPDATE:
You should also be aware that this can throw an exception if some of the files/folders are not accessible. See this question and another solution using Guava.

查看更多
登录 后发表回答