By Quintin Par


2010-01-13 11:29:32 8 Comments

How do I recursively list all files under a directory in Java? Does the framework provide any utility?

I saw a lot of hacky implementations. But none from the framework or nio

21 comments

@kanaparthikiran 2019-08-02 17:40:30

I came up with this for printing all the files/file names recursively.

private static void printAllFiles(String filePath,File folder) {
    if(filePath==null) {
        return;
    }
    File[] files = folder.listFiles();
    for(File element : files) {
        if(element.isDirectory()) {
            printAllFiles(filePath,element);
        } else {
            System.out.println(" FileName "+ element.getName());
        }
    }
}

@Brett Ryan 2014-06-03 03:37:29

Java 8 provides a nice stream to process all files in a tree.

Files.walk(Paths.get(path))
        .filter(Files::isRegularFile)
        .forEach(System.out::println);

This provides a natural way to traverse files. Since it's a stream you can do all nice stream operations on the result such as limit, grouping, mapping, exit early etc.

UPDATE: I might point out there is also Files.find which takes a BiPredicate that could be more efficient if you need to check file attributes.

Files.find(Paths.get(path),
           Integer.MAX_VALUE,
           (filePath, fileAttr) -> fileAttr.isRegularFile())
        .forEach(System.out::println);

Note that while the JavaDoc eludes that this method could be more efficient than Files.walk it is effectively identical, the difference in performance can be observed if you are also retrieving file attributes within your filter. In the end, if you need to filter on attributes use Files.find, otherwise use Files.walk, mostly because there are overloads and it's more convenient.

TESTS: As requested I've provided a performance comparison of many of the answers. Check out the Github project which contains results and a test case.

@Johnny 2015-01-15 13:13:33

One of those examples that can show the magic of functional programming even for the beginners.

@Sridhar Sarnobat 2015-06-25 22:18:37

How does the performance of this compare with pre-java 8 methods? My current directory traversal is too slow and I'm looking for something that will speed it up.

@Brett Ryan 2015-06-28 13:54:17

I'm writing up some tests containing most of the variants in the answers provided. So far, it seems that using Files.walk with a parallel stream is the best, followed closely by Files.walkFileTree which is only marginally slower. The accepted answer using commons-io is by far the slowest by my tests to be 4 times slower.

@Brett Ryan 2015-06-29 05:13:33

Tests are complete and a project added to Github, check it out for the results. The short answer is use any NIO flavour of the answers provided.

@Kachna 2015-09-05 08:58:07

@BrettRyan, I tried your solution but I get an exception Exception in thread "main" java.io.UncheckedIOException: java.nio.file.AccessDeniedException. How could I correct it

@thouliha 2015-10-09 15:58:08

How do I get an actual list of files from this?

@Brett Ryan 2015-10-10 00:58:15

@thouliha instead of forEach use collect with a set or list collector such as .collect(Collectors.toList()). If you can avoid a collector in your logic the better as you will be using less objects and processing can be faster.

@jFrenetic 2016-01-23 22:37:28

Wow, can't get my eyes off of this beautiful code. Who would've thought that one day Java would allow to implement such operations in one line.

@Matt Passell 2016-03-03 14:36:02

@BrettRyan am I correct that by default Files.walk() doesn't follow symbolic links? If so and one wanted to follow symlinks, it looks like the first chunk of code could instead be Files.walk(Paths.get(path), FileVisitOption.FOLLOW_LINKS)

@Brett Ryan 2016-03-10 22:31:46

Apologies for the delayed response @MattPassell, you are correct. There is a caveat to using this when a circular link is found, you won't end up with a recursive loop though you unfortunately will get a FileSystemLoopException being thrown which is wrapped in an UncheckedIOException

@Matt Passell 2016-03-11 15:32:21

@BrettRyan thanks, good point. In the particular spot I'm using it, the starting path might be a symlink, but from that point down, it isn't. That allowed me to do something like this Path basePath = Files.isSymbolicLink(basePath) ? Files.readSymbolicLink(basePath) : basePath; and then walk the tree without following links. :)

@Amalgovinus 2017-01-13 03:08:26

@BrettRyan "instead of forEach use collect" Sorry but I'm still unclear. Calling .collect(stagingFileList::add) on the resulting stream from that code gets me Collector<Path,A,R> is not a functional interface on the collect parameter. This stream stuff is cool but I'm not completely sure what I'm looking at anymore to fix this.

@Amalgovinus 2017-01-13 03:11:56

This is what I'm attempting-- Files.find( Paths.get(path), Integer.MAX_VALUE, (filePath, fileAttr) -> fileAttr.isRegularFile()) .collect(list::add);

@Brett Ryan 2017-01-13 03:43:13

@Amalgovinus what you're looking for is a collector, what you've given is a method reference. Replace list::add with Collectors.toList()

@Jonathan Hult 2017-01-16 05:45:30

@razor 2018-11-22 11:17:06

Files.walk looks nice, but quite often is useless.... it throws exception if you don't have an access to even one file... and you got nothing...

@Ebraheem Alrabee' 2017-10-30 17:14:31

This code is ready to run

public static void main(String... args) {
    File[] files = new File("D:/").listFiles();
    if (files != null) 
       getFiles(files);
}

public static void getFiles(File[] files) {
    for (File file : files) {
        if (file.isDirectory()) {
            getFiles(file.listFiles());
        } else {
            System.out.println("File: " + file);
        }
    }
}

@legendmohe 2018-06-23 09:05:49

    private void fillFilesRecursively(File file, List<File> resultFiles) {
        if (file.isFile()) {
            resultFiles.add(file);
        } else {
            for (File child : file.listFiles()) {
                fillFilesRecursively(child, resultFiles);
            }
        }
    }

@BullyWiiPlaza 2018-01-01 21:06:42

Here a simple but perfectly working solution using recursion:

public static List<Path> listFiles(String rootDirectory)
{
    List<Path> files = new ArrayList<>();
    listFiles(rootDirectory, files);

    return files;
}

private static void listFiles(String path, List<Path> collectedFiles)
{
    File root = new File(path);
    File[] files = root.listFiles();

    if (files == null)
    {
        return;
    }

    for (File file : files)
    {
        if (file.isDirectory())
        {
            listFiles(file.getAbsolutePath(), collectedFiles);
        } else
        {
            collectedFiles.add(file.toPath());
        }
    }
}

@Ralf R. 2017-10-12 10:43:07

Example outputs *.csv files in directory recursive searching Subdirectories using Files.find() from java.nio:

String path = "C:/Daten/ibiss/ferret/";
    logger.debug("Path:" + path);
    try (Stream<Path> fileList = Files.find(Paths.get(path), Integer.MAX_VALUE,
            (filePath, fileAttr) -> fileAttr.isRegularFile() && filePath.toString().endsWith("csv"))) {
        List<String> someThingNew = fileList.sorted().map(String::valueOf).collect(Collectors.toList());
        for (String t : someThingNew) {
            t.toString();
            logger.debug("Filename:" + t);
        }

    }

Posting this example, as I had trouble understanding howto pass the filename parameter in the #1 example given by Bryan, using foreach on Stream-result -

Hope this helps.

@chao 2014-11-22 15:15:24

With Java 7 you can use the following class:

import java.io.IOException;
import java.nio.file.FileVisitResult;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.SimpleFileVisitor;
import java.nio.file.attribute.BasicFileAttributes;

public class MyFileIterator extends SimpleFileVisitor<Path>
{
    public MyFileIterator(String path) throws Exception
    {
        Files.walkFileTree(Paths.get(path), this);
    }

    @Override
    public FileVisitResult visitFile(Path file,
            BasicFileAttributes attributes) throws IOException
    {
        System.out.println("File: " + file);
        return FileVisitResult.CONTINUE;
    }

    @Override
    public FileVisitResult preVisitDirectory(Path dir,
            BasicFileAttributes attributes) throws IOException
    {
        System.out.println("Dir: " + dir);
        return FileVisitResult.CONTINUE;
    }
}

@Rakesh Chaudhari 2017-06-23 05:25:44

You can use below code to get a list of files of specific folder or directory recursively.

public static void main(String args[]) {

        recusiveList("D:");

    }

    public static void recursiveList(String path) {

        File f = new File(path);
        File[] fl = f.listFiles();
        for (int i = 0; i < fl.length; i++) {
            if (fl[i].isDirectory() && !fl[i].isHidden()) {
                System.out.println(fl[i].getAbsolutePath());
                recusiveList(fl[i].getAbsolutePath());
            } else {
                System.out.println(fl[i].getName());
            }
        }
    }

@jjj 2019-02-16 12:33:09

this worked for me flawlessly... thank you

@Petrucio 2012-07-25 20:36:19

No external libraries needed.
Returns a Collection so you can do whatever you want with it after the call.

public static Collection<File> listFileTree(File dir) {
    Set<File> fileTree = new HashSet<File>();
    if(dir==null||dir.listFiles()==null){
        return fileTree;
    }
    for (File entry : dir.listFiles()) {
        if (entry.isFile()) fileTree.add(entry);
        else fileTree.addAll(listFileTree(entry));
    }
    return fileTree;
}

@Leo 2018-03-17 11:15:02

simple and clean

@sateesh 2010-01-13 12:53:58

Apart from the recursive traversal one can use a Visitor based approach as well.

Below code is uses Visitor based approach for the traversal.It is expected that the input to the program is the root directory to traverse.

public interface Visitor {
    void visit(DirElement d);
    void visit(FileElement f);
}

public abstract class Element {
    protected File rootPath;
    abstract void accept(Visitor v);

    @Override
    public String toString() {
        return rootPath.getAbsolutePath();
    }
}

public class FileElement extends Element {
    FileElement(final String path) {
        rootPath = new File(path);
    }

    @Override
    void accept(final Visitor v) {
        v.visit(this);
    }
}

public class DirElement extends Element implements Iterable<Element> {
    private final List<Element> elemList;
    DirElement(final String path) {
        elemList = new ArrayList<Element>();
        rootPath = new File(path);
        for (File f : rootPath.listFiles()) {
            if (f.isDirectory()) {
                elemList.add(new DirElement(f.getAbsolutePath()));
            } else if (f.isFile()) {
                elemList.add(new FileElement(f.getAbsolutePath()));
            }
        }
    }

    @Override
    void accept(final Visitor v) {
        v.visit(this);
    }

    public Iterator<Element> iterator() {
        return elemList.iterator();
    }
}

public class ElementWalker {
    private final String rootDir;
    ElementWalker(final String dir) {
        rootDir = dir;
    }

    private void traverse() {
        Element d = new DirElement(rootDir);
        d.accept(new Walker());
    }

    public static void main(final String[] args) {
        ElementWalker t = new ElementWalker("C:\\temp");
        t.traverse();
    }

    private class Walker implements Visitor {
        public void visit(final DirElement d) {
            System.out.println(d);
            for(Element e:d) {
                e.accept(this);
            }
        }

        public void visit(final FileElement f) {
            System.out.println(f);
        }
    }
}

@Bozho 2010-01-13 11:36:05

FileUtils have iterateFiles and listFiles methods. Give them a try. (from commons-io)

Edit: You can check here for a benchmark of different approaches. It seems that the commons-io approach is slow, so pick some of the faster ones from here (if it matters)

@andronikus 2012-04-27 17:53:13

FYI/TLDR: if you just want to list all files recursively with no filtering, do FileUtils.listFiles(dir, TrueFileFilter.INSTANCE, TrueFileFilter.INSTANCE), where dir is a File object that points to the base directory.

@schnatterer 2014-02-14 11:41:08

You might want to consider using listFilesAndDirs(), as listFiles() does not return empty folders.

@ocramot 2014-05-23 09:15:28

@MikeFHay Looking at the FileUtils code, I think that vould be FileUtils.listFiles(dir, true, true). using FileUtils.listFiles(dir, null, true) will throw an Exception, while FileUtils.listFiles(dir, true, null) will list all files without looking into subdirectories.

@Christian Bongiorno 2014-09-17 21:13:21

How about a JDK native library? I can implement this easy but I would simply be C&P from other places

@Brett Ryan 2015-06-28 13:58:18

I'm putting some tests together, but so far this seems to be performing 4 times slower than that of using JDK8 or JDK7 alternatives. Symlinks also prove to be problematic with this approach, especially where they link to directories higher in the tree, this causes the method to never return, this can be avoided by handling the filter, but unfortunately the symlinks themselves don't get visited even as a file.

@user1189332 2015-11-08 12:13:20

My version (of course I could have used the built in walk in Java 8 ;-) ):

public static List<File> findFilesIn(File rootDir, Predicate<File> predicate) {
        ArrayList<File> collected = new ArrayList<>();
        walk(rootDir, predicate, collected);
        return collected;
    }

    private static void walk(File dir, Predicate<File> filterFunction, List<File> collected) {
        Stream.of(listOnlyWhenDirectory(dir))
                .forEach(file -> walk(file, filterFunction, addAndReturn(collected, file, filterFunction)));
    }

    private static File[] listOnlyWhenDirectory(File dir) {
        return dir.isDirectory() ? dir.listFiles() : new File[]{};
    }

    private static List<File> addAndReturn(List<File> files, File toAdd, Predicate<File> filterFunction) {
        if (filterFunction.test(toAdd)) {
            files.add(toAdd);
        }
        return files;
    }

@stacker 2010-01-13 11:47:57

// Ready to run

import java.io.File;

public class Filewalker {

    public void walk( String path ) {

        File root = new File( path );
        File[] list = root.listFiles();

        if (list == null) return;

        for ( File f : list ) {
            if ( f.isDirectory() ) {
                walk( f.getAbsolutePath() );
                System.out.println( "Dir:" + f.getAbsoluteFile() );
            }
            else {
                System.out.println( "File:" + f.getAbsoluteFile() );
            }
        }
    }

    public static void main(String[] args) {
        Filewalker fw = new Filewalker();
        fw.walk("c:\\" );
    }

}

@Brett Ryan 2015-06-28 13:16:54

Just beware that for symbolic links that point to a path higher in the path hierarchy will cause the method to never end. Consider a path with a symlink that points to -> ..

@Tyler Nichols 2018-06-18 21:44:59

This is just essentially a bad implementation of Files.walkFileTree. I would reccomend that people look at FIles.walkFileTree instead of trying to roll it yourself... It has handling for the exact problem @BrettRyan pointed it.

@barrypicker 2019-07-14 19:22:02

Thank you for including import java.io.File;. So many examples forget to include the namespace stuff or even datatype stuff making the example a starting point on a voyage of discovery. Here this example is ready-to-run. Thanks.

@Roy Kachouh 2014-10-05 12:38:38

In Java 8, we can now use the Files utility to walk a file tree. Very simple.

Files.walk(root.toPath())
      .filter(path -> !Files.isDirectory(path))
      .forEach(path -> System.out.println(path));

@Nux 2014-01-21 09:32:36

Based on stacker answer. Here is a solution working in JSP without any external libraries so you can put it almost anywhere on your server:

<!DOCTYPE html>
<%@ page session="false" %>
<%@ page import="java.util.*" %>
<%@ page import="java.io.*" %>
<%@ page contentType="text/html; charset=UTF-8" %>

<%!
    public List<String> files = new ArrayList<String>();
    /**
        Fills files array with all sub-files.
    */
    public void walk( File root ) {
        File[] list = root.listFiles();

        if (list == null) return;

        for ( File f : list ) {
            if ( f.isDirectory() ) {
                walk( f );
            }
            else {
                files.add(f.getAbsolutePath());
            }
        }
    }
%>
<%
    files.clear();
    File jsp = new File(request.getRealPath(request.getServletPath()));
    File dir = jsp.getParentFile();
    walk(dir);
    String prefixPath = dir.getAbsolutePath() + "/";
%>

Then you just do something like:

    <ul>
        <% for (String file : files) { %>
            <% if (file.matches(".+\\.(apk|ipa|mobileprovision)")) { %>
                <li><%=file.replace(prefixPath, "")%></li>
            <% } %>
        <% } %>
    </ul>

@Samuel Kerrien 2015-06-15 09:54:34

While it probably works, the question is about file browsing, not rendering of browsed files. Better expose your algorithm as such, it is not a recommended practice to embed business logic inside a JSP.

@Nux 2015-06-24 12:22:05

That depends what you are doing. In an enterprise-size application you are absolutely right. If you just need this as a drop-in to a simple, standalone listing, then this is perfectly fine.

@bobah 2013-09-22 10:17:21

Non-recursive BFS with a single list (particular example is searching for *.eml files):

    final FileFilter filter = new FileFilter() {
        @Override
        public boolean accept(File file) {
            return file.isDirectory() || file.getName().endsWith(".eml");
        }
    };

    // BFS recursive search
    List<File> queue = new LinkedList<File>();
    queue.addAll(Arrays.asList(dir.listFiles(filter)));

    for (ListIterator<File> itr = queue.listIterator(); itr.hasNext();) {
        File file = itr.next();
        if (file.isDirectory()) {
            itr.remove();
            for (File f: file.listFiles(filter)) itr.add(f);
        }
    }

@yawn 2010-01-13 11:52:49

Java 7 will have has Files.walkFileTree:

If you provide a starting point and a file visitor, it will invoke various methods on the file visitor as it walks through the file in the file tree. We expect people to use this if they are developing a recursive copy, a recursive move, a recursive delete, or a recursive operation that sets permissions or performs another operation on each of the files.

There is now an entire Oracle tutorial on this question.

@benroth 2012-05-30 10:17:21

I prefer using a queue over recursion for this kind of simple traversion:

List<File> allFiles = new ArrayList<File>();
Queue<File> dirs = new LinkedList<File>();
dirs.add(new File("/start/dir/"));
while (!dirs.isEmpty()) {
  for (File f : dirs.poll().listFiles()) {
    if (f.isDirectory()) {
      dirs.add(f);
    } else if (f.isFile()) {
      allFiles.add(f);
    }
  }
}

@Wei 2013-02-01 05:54:45

But your algorithm cannot print with indented output. Dirs and files are messed. Any solution?

@Stefan Schmidt 2010-01-13 11:39:33

I would go with something like:

public void list(File file) {
    System.out.println(file.getName());
    File[] children = file.listFiles();
    for (File child : children) {
        list(child);
    }
}

The System.out.println is just there to indicate to do something with the file. there is no need to differentiate between files and directories, since a normal file will simply have zero children.

@hfs 2011-11-17 09:30:44

From the documentation of listFiles(): “If this abstract pathname does not denote a directory, then this method returns null.”

@Ben 2013-11-22 23:30:50

Improved variant public static Collection<File> listFileTree(File dir) { if (null == dir || !dir.isDirectory()) { return Collections.emptyList(); } final Set<File> fileTree = new HashSet<File>(); for (File entry : dir.listFiles()) { if (entry.isFile()) { fileTree.add(entry); } else { fileTree.addAll(listFileTree(entry)); } } return fileTree; }

@WillieT 2018-05-31 14:30:35

To me this is the most concise answer that is recursive.

@pstanton 2010-01-13 11:36:26

just write it yourself using simple recursion:

public List<File> addFiles(List<File> files, File dir)
{
    if (files == null)
        files = new LinkedList<File>();

    if (!dir.isDirectory())
    {
        files.add(dir);
        return files;
    }

    for (File file : dir.listFiles())
        addFiles(files, file);
    return files;
}

@helios 2010-01-13 11:44:00

Please! let the caller initialize the files list so it hasn't have to check its nullity each time. If you want create a second (public) method that creates the list, calls this internal method and returns the complete list.

@pstanton 2010-01-13 11:45:37

whatever. a null check isn't very expensive, convenience + personal preference aside i think he'll get the point.

@uday 2013-01-30 22:34:49

Can you explain little bit more verbosely?

@Michał Niklas 2010-01-13 11:35:53

I think this should do the work:

File dir = new File(dirname);
String[] files = dir.list();

This way you have files and dirs. Now use recursion and do the same for dirs (File class has isDirectory() method).

Related Questions

Sponsored Content

84 Answered Questions

[SOLVED] Is Java "pass-by-reference" or "pass-by-value"?

55 Answered Questions

[SOLVED] Creating a memory leak with Java

28 Answered Questions

[SOLVED] How to read a file line-by-line into a list?

58 Answered Questions

[SOLVED] How do I read / convert an InputStream into a String in Java?

65 Answered Questions

[SOLVED] How do I generate random integers within a specific range in Java?

  • 2008-12-12 18:20:57
  • user42155
  • 3854828 View
  • 3307 Score
  • 65 Answer
  • Tags:   java random integer

37 Answered Questions

[SOLVED] How do I check whether a file exists without exceptions?

57 Answered Questions

[SOLVED] How do I include a JavaScript file in another JavaScript file?

27 Answered Questions

[SOLVED] What is tail recursion?

31 Answered Questions

[SOLVED] When to use LinkedList over ArrayList in Java?

16 Answered Questions

[SOLVED] Standard concise way to copy a file in Java?

  • 2008-09-20 01:59:09
  • Peter
  • 257796 View
  • 417 Score
  • 16 Answer
  • Tags:   java file copy

Sponsored Content