last modified August 22, 2026
In this article we learn how to use SimpleFileVisitor to walk a
file tree in Java. We visit directories and files, search for matching paths,
handle traversal errors, and delete a directory tree.
SimpleFileVisitor is an adapter class from the
java.nio.file package. It implements the
FileVisitor<Path> interface with default implementations for
all visitor methods. We override only the callbacks that our operation needs.
The examples use Java 25's compact source-file syntax. With an earlier Java
version, place the code inside a class and use a conventional
public static void main(String[] args) method.
The Files.walkFileTree method starts at a given path and invokes a
visitor during the traversal. The two-argument overload walks the complete
tree using the default options.
import java.io.IOException;
import java.nio.file.FileVisitResult;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.SimpleFileVisitor;
import java.nio.file.attribute.BasicFileAttributes;
void main() throws IOException {
var root = Path.of(".");
Files.walkFileTree(root, new SimpleFileVisitor<Path>() {
@Override
public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) {
System.out.println(file);
return FileVisitResult.CONTINUE;
}
});
}
The visitor prints every file below the current directory. Directories are
visited as well, but they are not printed because this example overrides only
visitFile.
Files.walkFileTree(root, new SimpleFileVisitor<Path>() {
@Override
public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) {
System.out.println(file);
return FileVisitResult.CONTINUE;
}
});
The walkFileTree method receives the starting path and a visitor.
For every regular file, it calls visitFile with the path and its
BasicFileAttributes. Returning CONTINUE tells the
traversal to keep going.
The FileVisitor interface defines four callbacks. The
SimpleFileVisitor implementation supplies default behavior, so we
can override only the callbacks relevant to our task.
preVisitDirectory is called before the entries in a directory are visited.visitFile is called when a file is visited.visitFileFailed is called when a file cannot be visited.postVisitDirectory is called after all entries in a directory have been visited.
The callbacks return a FileVisitResult. The result controls what
happens next:
CONTINUE continues the traversal.SKIP_SUBTREE skips the remaining entries in the current directory.SKIP_SIBLINGS skips the remaining entries in the current directory and continues with the parent directory.TERMINATE stops the traversal immediately.
The overload with four arguments accepts traversal options and a maximum
depth. A depth of 0 visits only the starting path. A depth of
1 also visits entries directly below it.
import java.io.IOException;
import java.nio.file.FileVisitOption;
import java.nio.file.FileVisitResult;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.SimpleFileVisitor;
import java.nio.file.attribute.BasicFileAttributes;
import java.util.Set;
void main() throws IOException {
var root = Path.of(".");
var options = Set.<FileVisitOption>of();
Files.walkFileTree(root, options, 2, new SimpleFileVisitor<Path>() {
@Override
public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) {
System.out.println(file);
return FileVisitResult.CONTINUE;
}
});
}
This example visits the starting directory and its children to a maximum depth of two. The empty option set means that symbolic links are not followed.
The visitor can inspect each path and stop the traversal when it finds a match. In the following example, we print Java source files and continue walking the tree.
import java.io.IOException;
import java.nio.file.FileVisitResult;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.SimpleFileVisitor;
import java.nio.file.attribute.BasicFileAttributes;
void main() throws IOException {
var root = Path.of(".");
Files.walkFileTree(root, new SimpleFileVisitor<Path>() {
@Override
public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) {
var name = file.getFileName().toString();
if (name.endsWith(".java")) {
System.out.println(file);
}
return FileVisitResult.CONTINUE;
}
});
}
The getFileName method returns the final component of the path.
We compare its text with endsWith and ignore all other files.
We can prevent a directory and all of its children from being visited by
returning SKIP_SUBTREE from preVisitDirectory.
import java.io.IOException;
import java.nio.file.FileVisitResult;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.SimpleFileVisitor;
import java.nio.file.attribute.BasicFileAttributes;
void main() throws IOException {
var root = Path.of(".");
Files.walkFileTree(root, new SimpleFileVisitor<Path>() {
@Override
public FileVisitResult preVisitDirectory(Path dir,
BasicFileAttributes attrs) {
if (dir.getFileName() != null
&& dir.getFileName().toString().equals(".git")) {
return FileVisitResult.SKIP_SUBTREE;
}
return FileVisitResult.CONTINUE;
}
@Override
public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) {
System.out.println(file);
return FileVisitResult.CONTINUE;
}
});
}
When the visitor reaches a directory named .git, it skips that
directory and everything below it. The traversal then continues with the next
entry in the parent directory.
Permission problems, broken links, and other I/O errors can prevent a path
from being visited. Override visitFileFailed when the application
should report the problem and continue with other paths.
import java.io.IOException;
import java.nio.file.FileVisitResult;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.SimpleFileVisitor;
import java.nio.file.attribute.BasicFileAttributes;
void main() throws IOException {
var root = Path.of(".");
Files.walkFileTree(root, new SimpleFileVisitor<Path>() {
@Override
public FileVisitResult visitFileFailed(Path file, IOException exc) {
System.err.println("Could not visit " + file + ": " + exc.getMessage());
return FileVisitResult.CONTINUE;
}
@Override
public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) {
System.out.println(file);
return FileVisitResult.CONTINUE;
}
});
}
Returning CONTINUE ignores the failure for traversal purposes; it
does not repair the underlying permission or I/O problem. If a failed visit
must abort the operation, rethrow the exception or return
TERMINATE according to the application's error policy.
Deleting files is a common use of SimpleFileVisitor. Files must be
deleted before their containing directories, so we delete files in
visitFile and directories in postVisitDirectory.
This example is destructive. Confirm the root path before running it and use a test directory first.
import java.io.IOException;
import java.nio.file.FileVisitResult;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.SimpleFileVisitor;
import java.nio.file.attribute.BasicFileAttributes;
void main() throws IOException {
var root = Path.of("temporary-directory");
Files.walkFileTree(root, new SimpleFileVisitor<Path>() {
@Override
public FileVisitResult visitFile(Path file, BasicFileAttributes attrs)
throws IOException {
Files.delete(file);
return FileVisitResult.CONTINUE;
}
@Override
public FileVisitResult postVisitDirectory(Path dir, IOException exc)
throws IOException {
if (exc != null) {
throw exc;
}
Files.delete(dir);
return FileVisitResult.CONTINUE;
}
});
}
The postVisitDirectory callback runs after the directory's
contents have been processed. This order allows the directory to be removed
only after all of its files and child directories have been deleted.
By default, walkFileTree does not follow symbolic links. To follow
them, pass FileVisitOption.FOLLOW_LINKS in the option set.
Following links can cause a cycle or make the traversal leave the intended
directory, so use the option only when it is required.
import java.nio.file.FileVisitOption; import java.util.Set; var options = Set.of(FileVisitOption.FOLLOW_LINKS);
When following links, the traversal can throw a
FileSystemLoopException if it detects a cycle. Code that follows
links should also consider permissions, mount points, and the possibility that
the same file is reachable through more than one path.
Java SimpleFileVisitor - language reference
Files.walkFileTree - language reference
My name is Jan Bodnar, and I am a passionate programmer with extensive programming experience. I have been writing programming articles since 2007. To date, I have authored over 1,400 articles and 8 e-books. I possess more than ten years of experience in teaching programming.
List all Java tutorials.