ZetCode

Java SimpleFileVisitor

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.

Walking a file tree

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.

Main.java
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.

Visitor methods

The FileVisitor interface defines four callbacks. The SimpleFileVisitor implementation supplies default behavior, so we can override only the callbacks relevant to our task.

The callbacks return a FileVisitResult. The result controls what happens next:

Limiting the traversal

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.

Main.java
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.

Finding files

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.

Main.java
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.

Skipping directories

We can prevent a directory and all of its children from being visited by returning SKIP_SUBTREE from preVisitDirectory.

Main.java
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.

Handling visit failures

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.

Main.java
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 a directory tree

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.

Main.java
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.

Following symbolic links

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.

Source

Java SimpleFileVisitor - language reference

Files.walkFileTree - language reference

Author

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.