204

I need to get a list of all the files in a directory, including files in all the sub-directories. What is the standard way to accomplish directory iteration with Java?

0

11 Answers 11

251

You can use File#isDirectory() to test if the given file (path) is a directory. If this is true, then you just call the same method again with its File#listFiles() outcome. This is called recursion.

Here's a basic kickoff example:

package com.stackoverflow.q3154488; import java.io.File; public class Demo { public static void main(String... args) { File dir = new File("/path/to/dir"); showFiles(dir.listFiles()); } public static void showFiles(File[] files) { for (File file : files) { if (file.isDirectory()) { System.out.println("Directory: " + file.getAbsolutePath()); showFiles(file.listFiles()); // Calls same method again. } else { System.out.println("File: " + file.getAbsolutePath()); } } } } 

Note that this is sensitive to StackOverflowError when the tree is deeper than the JVM's stack can hold. If you're already on Java 8 or newer, then you'd better use Files#walk() instead which utilizes tail recursion:

package com.stackoverflow.q3154488; import java.io.File; import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; public class DemoWithJava8 { public static void main(String... args) throws Exception { Path dir = Paths.get("/path/to/dir"); Files.walk(dir).forEach(path -> showFile(path.toFile())); } public static void showFile(File file) { if (file.isDirectory()) { System.out.println("Directory: " + file.getAbsolutePath()); } else { System.out.println("File: " + file.getAbsolutePath()); } } } 
Sign up to request clarification or add additional context in comments.

6 Comments

thanks Balus, any idea on how deep that may be as a general guess?
Depends on your JVM's memory settings. But generally something like a few thousand. If you think you might ever run into a directory like that, then don't use recursion.
This is susceptible to a NullPointerException when the file system changes between the call to isDirectory and listFiles as might happen if System.out.println blocks or you just get really unlucky. Checking that the output of listFiles is not null would solve that race condition.
@MikeSamuel - If the directory has 10's of thousands of small files with big names, and you store all file names in an array at once, then JVM could run out of memory, right ? So, is there a way to iterate one by one or in small batches ?
@BoratSagdiyev, Not using the old Java file APIs, but if you're on a modern JVM then the java.nio.file.DirectoryStream allows you to iterate over a directory, and could be implemented to have a small memory footprint but the only way to tell for sure would be to monitor memory usage on a particular platform.
|
101

If you are using Java 1.7, you can use java.nio.file.Files.walkFileTree(...).

For example:

public class WalkFileTreeExample { public static void main(String[] args) { Path p = Paths.get("/usr"); FileVisitor<Path> fv = new SimpleFileVisitor<Path>() { @Override public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException { System.out.println(file); return FileVisitResult.CONTINUE; } }; try { Files.walkFileTree(p, fv); } catch (IOException e) { e.printStackTrace(); } } } 

If you are using Java 8, you can use the stream interface with java.nio.file.Files.walk(...):

public class WalkFileTreeExample { public static void main(String[] args) { try (Stream<Path> paths = Files.walk(Paths.get("/usr"))) { paths.forEach(System.out::println); } catch (IOException e) { e.printStackTrace(); } } } 

2 Comments

is there a way with the streams to put a checkpoint when a new directory is walked and execute a function?
Files.walk(somePath) will walk you through the whole file and directory tree accessible from that root directory. If you need to process only certain files, i.e. by their extension, you can use a filter with PathMatcher that you configured to glob:**.xml i.e. to omit any non-XML files in later stages of the pipeline
29

Check out the FileUtils class in Apache Commons - specifically iterateFiles:

Allows iteration over the files in given directory (and optionally its subdirectories).

3 Comments

This API isn't truly streaming (if you care about mem usage), it first generate a collection, only then returns an iterator over it: return listFiles(directory, fileFilter, dirFilter).iterator();
Good option for Java 1.6.
Agree with @GiliNachum. FileUtils by Apache first collects all files and gives an iterator for them. It is harmful for resources if you have a huge amount of files.
9

Using org.apache.commons.io.FileUtils

File file = new File("F:/Lines"); Collection<File> files = FileUtils.listFiles(file, null, true); for(File file2 : files){ System.out.println(file2.getName()); } 

Use false if you do not want files from sub directories.

Comments

8

For Java 7+, there is also https://docs.oracle.com/javase/7/docs/api/java/nio/file/DirectoryStream.html

Example taken from the Javadoc:

List<Path> listSourceFiles(Path dir) throws IOException { List<Path> result = new ArrayList<>(); try (DirectoryStream<Path> stream = Files.newDirectoryStream(dir, "*.{c,h,cpp,hpp,java}")) { for (Path entry: stream) { result.add(entry); } } catch (DirectoryIteratorException ex) { // I/O error encounted during the iteration, the cause is an IOException throw ex.getCause(); } return result; } 

Comments

3

It's a tree, so recursion is your friend: start with the parent directory and call the method to get an array of child Files. Iterate through the child array. If the current value is a directory, pass it to a recursive call of your method. If not, process the leaf file appropriately.

Comments

2

As noted, this is a recursion problem. In particular, you may want to look at

listFiles() 

In the java File API here. It returns an array of all the files in a directory. Using this along with

isDirectory() 

to see if you need to recurse further is a good start.

1 Comment

This link may be of use since the one in the answer is broken.
1

You can also misuse File.list(FilenameFilter) (and variants) for file traversal. Short code and works in early java versions, e.g:

// list files in dir new File(dir).list(new FilenameFilter() { public boolean accept(File dir, String name) { String file = dir.getAbsolutePath() + File.separator + name; System.out.println(file); return false; } }); 

Comments

0

To add with @msandiford answer, as most of the times when a file tree is walked u may want to execute a function as a directory or any particular file is visited. If u are reluctant to using streams. The following methods overridden can be implemented

Files.walkFileTree(Paths.get(Krawl.INDEXPATH), EnumSet.of(FileVisitOption.FOLLOW_LINKS), Integer.MAX_VALUE, new SimpleFileVisitor<Path>() { @Override public FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes attrs) throws IOException { // Do someting before directory visit return FileVisitResult.CONTINUE; } @Override public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException { // Do something when a file is visited return FileVisitResult.CONTINUE; } @Override public FileVisitResult postVisitDirectory(Path dir, IOException exc) throws IOException { // Do Something after directory visit return FileVisitResult.CONTINUE; } }); 

Comments

0

I like to use Optional and streams to have a net and clear solution, i use the below code to iterate over a directory. the below cases are handled by the code:

  1. handle the case of empty directory
  2. Laziness

but as mentioned by others, you still have to pay attention for outOfMemory in case you have huge folders

 File directoryFile = new File("put your path here"); Stream<File> files = Optional.ofNullable(directoryFile// directoryFile .listFiles(File::isDirectory)) // filter only directories(change with null if you don't need to filter) .stream() .flatMap(Arrays::stream);// flatmap from Stream<File[]> to Stream<File> 

Comments

0

If you need only to list the file names you can use this:

Files.walk(dirPath).filter(Files::isRegularFile).forEach(System.out::println); 

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.