This article is based on The Well-Grounded Java Developer, to be published Summer-2011. It is being reproduced here by permission from Manning Publications. Manning publishes MEAP (Manning Early Access Program,) eBooks and pBooks. MEAPs are sold exclusively through Manning.com. All pBook purchases include free PDF, mobi and epub. When mobile formats become available all customers will be contacted and upgraded. Visit Manning.com for more information. [ Use promotional code ‘java40beat’ and get 40% discount on eBooks and pBooks ]
also read:
Directory Trees in Java 7.0
Introduction
Welcome to J The ability to navigate directories has been given a major overhaul in Java 7. The addition of the new java.nio.file.DirectoryStreaminterface and its implementing classes allow you to perform the following broad functions:
- Iterate over entries in a directory
- Perform recursive move, copy, and delete operations via the walkFileTree method
- Deal with large directory structures
- Filter entries using regular expressions and MIME based content detection
We’ll explicitly cover the first two points1 (iterating over entries and walking the directory tree), starting with a simple example of iterating over a list of directory entries and filtering some out.
Iterating over a directory listing
First, we’ll cover the simple example of using a pattern matching filter to list all of the .java files in a project directory, as shown in listing 1.
Listing 1 Listing Java source code in a directory
try { Path dir = Paths.get("C:\workspace\java7developer\src"); #1 DirectoryStream<Path> stream = dir.newDirectoryStream("*.java"); #2 for (Path entry: stream) #3 { #3 System.out.println(entry.getName()); #3 } #3 } catch (IOException e) { e.printStackTrace(); } #1 Starting path #2 Declares a filtering stream #3 Lists each .java file
You start by declaring the familiar Paths.getPath(String path) call (#1). The key part comes with the creation of the new DirectoryStream(String patternMatch) (#2), which returns a filtered DirectoryStream. Lastly we show that we’ve only got the .java files by printing out each entry (#3).
The example above shows the power of the new API when dealing with a single directory. But, what if you need to recursively filter across multiple directories?
Walking the directory tree
Walking a directory tree is a new feature in Java 7 and you will need to know a number of interfaces and implementation details in order to use it to its full potential. The key method to use for walking the directory is:
Files.walkFileTree(Path startingDir, FileVisitor<? super Path> visitor);
Providing the startingDir is easy enough but, in order to provide an implementation of the FileVisitor interface (e.g., provide the tricky looking FileVisitor<? super Path> visitor parameter) it gets a bit trickier as you need to implement at least five methods:
- FileVisitResult preVisitDirectory(T dir)
- FileVisitResult preVisitDirectoryFailed(T dir, IOException exc)
- FileVisitResult visitFile(T file, BasicFileAttributes attrs)
- FileVisitResult visitFileFailed(T file, IOException exc)
- FileVisitResult postVisitDirectory(T dir, IOException exc)
Looks like a good deal of work right? Well it is but, luckily, the API designers have supplied a default implementation, the SimpleFileVisitor<T>. Carrying on from our previous example of listing .java source files in a directory listing, we now list .java source files from all of the directories that sit underneath C:\workspace\java7developer\src. Listing 2 demonstrates this use of the walkFileTree method.
Listing 2 Listing Java source code in subdirectories
public class Find { public static void main(String[] args) throws IOException { Path startingDir = Paths.get("C:\workspace\java7developer\src"); #A Files.walkFileTree(startingDir, new FindJavaVisitor()); #1 } private static class FindJavaVisitor extends SimpleFileVisitor<Path> #2 { public FindJavaVisitor() {}; public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) #3 { if ((file != null) && (attrs != null)) { if (file.getName().toString().endsWith(".java")) { System.out.println(file.getName().toString()); } } return FileVisitResult.CONTINUE; } } } #A Starting directory #1 Calls to walkTheTree #2 Implementation of SimpleFileVisitor<Path> #3 Overrides visitFile
We start by calling the Files.walkFileTree method (#1). The key point to take in here is that we’re passing in FindJavaVisitor, which extends SimpleFileVisitor (#2). In other words, we want SimpleFileVisitor to do most of the work for us, traversing the directories, and so on. The only code we have to write is when we override the visitFile(Path, BasicFileAttributes) method (#3), in which we write some simple Java to see if a file ends with .java and to echo it out to stdout if it does.
Other use cases could be to recursively move, copy, delete, or otherwise modify files. In most cases, you’ll only need to extend SimpleFileVisitor, but the flexibility is there in the API if you want to implement your own complete FileVisitor.
Summary
We talked about the specific support put in place in Java 7 for dealing with directories. Specifically, we discussed iterating over a directory listing and walking the directory tree.