![]() | |
|
The new FileVisitor
Java 7 NIO.2 API allows you to implement scenario in which you want to traverse a directory tree recursively, stopping
at each file and directory under that tree and having your own callback methods invoked for each entry found. In previous Java versions, this would have
been a painful process involving recursively listing directories, inspecting their entries, and invoking the callbacks yourself. In Java 7, this is all
provided via the FileVisitor
API:
public interface FileVisitor<T> { FileVisitResult preVisitDirectory(T dir, BasicFileAttributes attrs) throws IOException; FileVisitResult visitFile(T file, BasicFileAttributes attrs) throws IOException; FileVisitResult visitFileFailed(T file, IOException exc) throws IOException; FileVisitResult postVisitDirectory(T dir, IOException exc) throws IOException; }
public enum FileVisitResult { /** * Continue. When returned from a FileVisitor#preVisitDirectory method then the entries in the * directory should also be visited. */ CONTINUE, /** * Terminate. */ TERMINATE, /** * Continue without visiting the entries in this directory. This result is only meaningful when * returned from the FileVisitor#preVisitDirectory method; otherwise this result type is the * same as returning CONTINUE. */ SKIP_SUBTREE, /** * Continue without visiting the siblings of this file or directory. If returned from the * FileVisitor#preVisitDirectory method then the entries in the directory are also skipped * and the FileVisitor#postVisitDirectory method is not invoked. */ SKIP_SIBLINGS; }
The first step is to implement your own FileVisitor
class. This class contains the callback methods that the file-visitor engine will invoke
as it traverses the file system. The FileVisitor
interface consists of four methods, listed here in the typical order they would be called
during traversal (T
here stands for either java.nio.file.Path
or a superclass):
FileVisitResult preVisitDirectory(T dir, BasicFileAttributes attrs)
is called before the entries in that directory are visited.
It returns one of the FileVisitResult
's enum values to tell the file visitor API what to do next.
If this method returns FileVisitResult.CONTINUE
, then entries in the directory are visited. If this method returns
FileVisitResult.SKIP_SUBTREE
or FileVisitResult.SKIP_SIBLINGS
then entries in the directory (and any
descendants) will not be visited.
FileVisitResult visitFile(T file, BasicFileAttributes attrs)
is called when a file in the current directory is being visited.
The attributes for this file are passed into the second parameter.
FileVisitResult visitFileFailed(T file, IOException exc)
is called when the visit to a file has failed. The second parameter
specifies the exception that caused the visit to fail.
This method is invoked if the file's attributes could not be read, the file is a directory that could not be opened, and other reasons.
FileVisitResult postVisitDirectory(T dir, IOException exc)
is called after the visit to a directory and all its subdirectories
has completed. The exception parameter is null
when the directory visit has been successful, or it contains the exception that
caused the directory visit to end prematurely.
To help developers save time, NIO.2 has provided an implementation of the FileVisitor
interface: java.nio.file.SimpleFileVisitor
.
This class is as basic as it gets: for the xxxxxFailed()
methods, it just rethrows the exception, and for the other methods it continues
without doing anything at all. What is useful about this class is that you can use anonymous classes to override only the methods you want; the rest of
the methods are implemented by default.
Code below shows how to create anonymous inner FileVisitor
instance:
FileVisitor<Path> myFileVisitor = new SimpleFileVisitor<Path>() { @Override public FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes attrs) { System.out.println(String.format("Before visit the '%s' directory", dir)); return FileVisitResult.CONTINUE; } @Override public FileVisitResult visitFile(Path file, BasicFileAttributes attribs) { System.out.println(String.format("Visiting file '%s' which has size %d bytes", file, attribs.size())); return FileVisitResult.CONTINUE; } };
The FileVisitor
implementation from code above should print a message for each directory and file it visits and also give the size
of the files from their BasicFileAttributes
.
Next we want to create a Path
from which to start our file visiting. This is done using the java.nio.file.Paths
class:
Path headDir = Paths.get("C:\\home");
We can use either of two methods on the java.nio.file.Files
class to start the tree traversal:
public static Path walkFileTree(Path start, FileVisitor<? super Path> visitor) throws IOException
Walks the file tree under the head directory, invoking the callback methods implemented in FileVisitor
as it goes.
It does not follow symbolic links, and visits all levels of the file tree.
public static Path walkFileTree(Path start, Set<FileVisitOption> options, int maxDepth, FileVisitor<? super Path> visitor) throws IOException
Similar to the preceding method but gives you two additional parameters to specify visit options and how many directories deep into the file tree the traversal should go.
We will use the simpler version of the walkFileTree(...)
method to start the process of walking the file tree:
Files.walkFileTree(headDir, myFileVisitor);
it shows the output similar to this:
Before visit the 'C:\home' directory Before visit the 'C:\home\zaikin' directory Before visit the 'C:\home\zaikin\foo' directory Before visit the 'C:\home\zaikin\foo\company' directory Visiting file 'C:\home\zaikin\foo\company\readme.txt' which has size 2 bytes Before visit the 'C:\home\zaikin\foo\sample' directory Visiting file 'C:\home\zaikin\foo\test.txt' which has size 7 bytes
As you can see, the file traversal is depth first but not necessarily in any alphabetical order within a directory. Our callback methods were invoked as expected, and we can see that all the files in the tree have been listed and all the directories have been visited.
![]() ![]() ![]() |