Get size of folder or file
Asked Answered
A

19

122

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

Audile answered 27/1, 2010 at 19:44 Comment(2)
Same but with focus on efficiency: stackoverflow.com/questions/116574/…Quackenbush
If you happen to be on Android then take a look at StatFs. It uses file system statistics and is nearly 1000x faster than recursive methods, which were unusable for our needs. Our implementation can be found here: https://mcmap.net/q/16816/-android-fast-and-efficient-way-of-finding-a-directory-sizeBipetalous
C
203
java.io.File file = new java.io.File("myfile.txt");
file.length();

This returns the length of the file in bytes or 0 if the file does not exist. There is no built-in way to get the size of a folder, you are going to have to walk the directory tree recursively (using the listFiles() method of a file object that represents a directory) and accumulate the directory size for yourself:

public static long folderSize(File directory) {
    long length = 0;
    for (File file : directory.listFiles()) {
        if (file.isFile())
            length += file.length();
        else
            length += folderSize(file);
    }
    return length;
}

WARNING: This method is not sufficiently robust for production use. directory.listFiles() may return null and cause a NullPointerException. Also, it doesn't consider symlinks and possibly has other failure modes. Use this method.

Conditioner answered 27/1, 2010 at 19:48 Comment(4)
Be careful if you run this in the C: root directory on a Windows machine; there's a system file there which is (according to java.io.File) neither a file nor a directory. You might want to change the else-clause to check that the File is actually a directory.Gaiseric
Simple change to check the parameter to see if it is not a directory at the beginning of the method and return the length then the recursion is simpler - just add the call to self in the same method and then this supports passing in a file reference instead of a directory as well.Pronation
If you use Java 7 or higher, use the answer https://mcmap.net/q/16815/-get-size-of-folder-or-file it is a lot faster.Petropavlovsk
This will be confused by symlinks. Also, it may throw a NullPointerException if the directory is concurrently modified.Hyaluronidase
J
48

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();
}
Johanajohanan answered 9/11, 2013 at 15:0 Comment(7)
Is there an equivalent for this on Android development?Upward
Is there a reason for using AtomicLong instead of just long?Recalesce
The variable has to be final when accessed from anonymous classJohanajohanan
I did a benchmark using JMH and this NIO api method is about 4 to 5 times faster compared to the commons-io code (tested on a folder with many subfolders for a total of 180229 files). Commons IO took 15 seconds, NIO took 5 seconds.Petropavlovsk
This approach is the most robust. It deals with symlinks, concurrent modification, security exceptions, works with both files and directories, etc. It's too bad Files doesn't support it directly!Hyaluronidase
@Alexanderdubinsky, maybe, but you broke the formatingJohanajohanan
the method is damn fast compared to apache.ioStortz
K
41

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.

Kinematograph answered 1/7, 2012 at 20:31 Comment(4)
So what happens when file is not a directory ? when it doesn't exist ? etc - how awful docsOsrick
@Osrick - Just copy and paste the lines after the checkDirectory(directory); check. Just make sure that File.listFiles has children. Refs: FileUtils.sizeOfDirectory(), File.listFiles()Ronaldronalda
See bug IO-449. This method will throw an IllegalArgumentException if the directory is modified while it is iterating.Hyaluronidase
ouch!!! That sucks...yeah, it lists files and then if one is deleted while the code is running, it throws.Mignonne
R
23

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.

Rest answered 14/7, 2014 at 10:18 Comment(2)
i was looking into something similiar and ended up with the code in question: stackoverflow.com/questions/22867286/… , as you see there is another aspect of error handling also causing problems.Johanajohanan
@AkselWillgert Thanks, this is unfortunate and I've updated the answer. Now switching to Guava https://mcmap.net/q/16972/-files-walk-calculate-total-sizeRest
L
10
public static long getFolderSize(File dir) {
    long size = 0;
    for (File file : dir.listFiles()) {
        if (file.isFile()) {
            System.out.println(file.getName() + " " + file.length());
            size += file.length();
        }
        else
            size += getFolderSize(file);
    }
    return size;
}
Lim answered 27/1, 2010 at 19:49 Comment(4)
@Lim your code need to have a simple fix, in the recursive call, you should add the size to existing size not just assign to it. size += getFolderSize(file);Vicereine
@Teja: Thanks for pointing out, but the changes will be in the if statement as wellLim
Sometimes on a growing folder (another thread is downloading files and folders and at the same time I'm printing folder size as progressing) it gives nullpointerexception at line "for (File file : dir.listFiles()) {". Some files appear and disappear quickly on a living folder. So I added a null check for dir.listFiles() return value before for loop.Regnant
From File.listFiles() javadoc: "The array will be empty if the directory is empty. Returns null if this abstract pathname does not denote a directory, or if an I/O error occurs." So above comment is useful when getting folder size on dynamically changing folders.Regnant
M
8

For Java 8 this is one right way to do it:

Files.walk(new File("D:/temp").toPath())
                .map(f -> f.toFile())
                .filter(f -> f.isFile())
                .mapToLong(f -> f.length()).sum()

It is important to filter out all directories, because the length method isn't guaranteed to be 0 for directories.

At least this code delivers the same size information like Windows Explorer itself does.

Merger answered 21/2, 2017 at 14:4 Comment(0)
P
5

Here's the best way to get a general File's size (works for directory and non-directory):

public static long getSize(File file) {
    long size;
    if (file.isDirectory()) {
        size = 0;
        for (File child : file.listFiles()) {
            size += getSize(child);
        }
    } else {
        size = file.length();
    }
    return size;
}

Edit: Note that this is probably going to be a time-consuming operation. Don't run it on the UI thread.

Also, here (taken from https://mcmap.net/q/16973/-format-file-size-as-mb-gb-etc-duplicate) is a nice way to get a user-readable String from the long returned:

public static String getReadableSize(long size) {
    if(size <= 0) return "0";
    final String[] units = new String[] { "B", "KB", "MB", "GB", "TB" };
    int digitGroups = (int) (Math.log10(size)/Math.log10(1024));
    return new DecimalFormat("#,##0.#").format(size/Math.pow(1024, digitGroups))
            + " " + units[digitGroups];
}
Peracid answered 22/8, 2014 at 4:52 Comment(0)
U
4

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.

Unemployable answered 27/1, 2010 at 19:46 Comment(0)
R
4

The File object has a length method:

f = new File("your/file/name");
f.length();
Revulsion answered 27/1, 2010 at 19:47 Comment(0)
O
4

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.

Openwork answered 4/3, 2017 at 18:18 Comment(0)
F
3
  • Works for Android and Java
  • Works for both folders and files
  • Checks for null pointer everywhere where needed
  • Ignores symbolic link aka shortcuts
  • Production ready!

Source code:

   public long fileSize(File root) {
        if(root == null){
            return 0;
        }
        if(root.isFile()){
            return root.length();
        }
        try {
            if(isSymlink(root)){
                return 0;
            }
        } catch (IOException e) {
            e.printStackTrace();
            return 0;
        }

        long length = 0;
        File[] files = root.listFiles();
        if(files == null){
            return 0;
        }
        for (File file : files) {
            length += fileSize(file);
        }

        return length;
    }

    private static boolean isSymlink(File file) throws IOException {
        File canon;
        if (file.getParent() == null) {
            canon = file;
        } else {
            File canonDir = file.getParentFile().getCanonicalFile();
            canon = new File(canonDir, file.getName());
        }
        return !canon.getCanonicalFile().equals(canon.getAbsoluteFile());
    }
Fosdick answered 15/10, 2017 at 15:15 Comment(0)
A
2

I've tested du -c <folderpath> and is 2x faster than nio.Files or recursion

private static long getFolderSize(File folder){
  if (folder != null && folder.exists() && folder.canRead()){
    try {
      Process p = new ProcessBuilder("du","-c",folder.getAbsolutePath()).start();
      BufferedReader r = new BufferedReader(new InputStreamReader(p.getInputStream()));
      String total = "";
      for (String line; null != (line = r.readLine());)
        total = line;
      r.close();
      p.waitFor();
      if (total.length() > 0 && total.endsWith("total"))
        return Long.parseLong(total.split("\\s+")[0]) * 1024;
    } catch (Exception ex) {
      ex.printStackTrace();
    }
  }
  return -1;
}
Annamaeannamaria answered 10/5, 2020 at 19:11 Comment(0)
B
1

for windows, using java.io this reccursive function is useful.

    public static long folderSize(File directory) {
    long length = 0;

    if (directory.isFile())
         length += directory.length();
    else{
        for (File file : directory.listFiles()) {
             if (file.isFile())
                 length += file.length();
             else
                 length += folderSize(file);
        }
    }

    return length;
}

This is tested and working properly on my end.

Bakerman answered 17/7, 2019 at 11:30 Comment(0)
G
1
private static long getFolderSize(Path folder) {
        try {
            return Files.walk(folder)
                      .filter(p -> p.toFile().isFile())
                      .mapToLong(p -> p.toFile().length())
                      .sum();
        } catch (IOException e) {
            e.printStackTrace();
            return 0L;
        }
Graeco answered 24/12, 2019 at 8:18 Comment(2)
Although your code looks good, I'm not sure it adds anything to the other answers. If it does, then please edit your answer to explain.Wellappointed
It's just an updated version of doing the same job in less lines of code.Graeco
E
0
public long folderSize (String directory)
    {
        File curDir = new File(directory);
        long length = 0;
        for(File f : curDir.listFiles())
        {
            if(f.isDirectory())
            {               
                 for ( File child : f.listFiles()) 
                 {
                     length = length + child.length();
                 }

                System.out.println("Directory: " + f.getName() + " " + length + "kb");
            }
            else
            {
                length = f.length();
                System.out.println("File: " + f.getName() + " " + length + "kb");
            }
            length = 0;
        }
        return length;
    }
Ethanethane answered 5/10, 2014 at 18:49 Comment(0)
R
0

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;
}
Rhettrhetta answered 21/1, 2017 at 16:23 Comment(0)
C
0

in linux if you want to sort directories then du -hs * | sort -h

Cosmopolitan answered 31/3, 2017 at 19:27 Comment(0)
W
0

You can use Apache Commons IO to find the folder size easily.

If you are on maven, please add the following dependency in your pom.xml file.

<!-- https://mvnrepository.com/artifact/commons-io/commons-io -->
<dependency>
    <groupId>commons-io</groupId>
    <artifactId>commons-io</artifactId>
    <version>2.6</version>
</dependency>

If not a fan of Maven, download the following jar and add it to the class path.

https://repo1.maven.org/maven2/commons-io/commons-io/2.6/commons-io-2.6.jar

public long getFolderSize() {

    File folder = new File("src/test/resources");
    long size = FileUtils.sizeOfDirectory(folder);

    return size; // in bytes
}

To get file size via Commons IO,

File file = new File("ADD YOUR PATH TO FILE");

long fileSize = FileUtils.sizeOf(file);

System.out.println(fileSize); // bytes

It is also achievable via Google Guava

For Maven, add the following:

<!-- https://mvnrepository.com/artifact/com.google.guava/guava -->
<dependency>
    <groupId>com.google.guava</groupId>
    <artifactId>guava</artifactId>
    <version>28.1-jre</version>
</dependency>

If not using Maven, add the following to class path

https://repo1.maven.org/maven2/com/google/guava/guava/28.1-jre/guava-28.1-jre.jar

public long getFolderSizeViaGuava() {
        File folder = new File("src/test/resources");
        Iterable<File> files = Files.fileTreeTraverser()
                .breadthFirstTraversal(folder);
        long size = StreamSupport.stream(files.spliterator(), false)
                .filter(f -> f.isFile())
                .mapToLong(File::length).sum();

        return  size;
    }

To get file size,

 File file = new File("PATH TO YOUR FILE");
 long s  = file.length();
 System.out.println(s);
Wont answered 11/11, 2019 at 1:52 Comment(0)
S
0
fun getSize(context: Context, uri: Uri?): Float? {
    var fileSize: String? = null
    val cursor: Cursor? = context.contentResolver
        .query(uri!!, null, null, null, null, null)
    try {
        if (cursor != null && cursor.moveToFirst()) {

            // get file size
            val sizeIndex: Int = cursor.getColumnIndex(OpenableColumns.SIZE)
            if (!cursor.isNull(sizeIndex)) {
                fileSize = cursor.getString(sizeIndex)
            }
        }
    } finally {
        cursor?.close()
    }
    return fileSize!!.toFloat() / (1024 * 1024)
}
Synchrotron answered 23/12, 2021 at 12:45 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.