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?
11 Answers
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()); } } } 6 Comments
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.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.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
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 pipelineCheck out the FileUtils class in Apache Commons - specifically iterateFiles:
Allows iteration over the files in given directory (and optionally its subdirectories).
3 Comments
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
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.
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
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
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:
- handle the case of empty directory
- 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>