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?
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());
}
}
}
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. –
Kei 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. –
Kei DirectoryStream
please refer to the answer of Wim Deblauwe as it lists important aspect. The stream should be closed to prevent resource leak. –
Drawee 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();
}
}
}
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 –
Barnwell Check out the FileUtils class in Apache Commons - specifically iterateFiles:
Allows iteration over the files in given directory (and optionally its subdirectories).
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.
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;
}
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.
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;
}
});
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;
}
});
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>
© 2022 - 2024 — McMap. All rights reserved.