I’ve been preparing for some upcoming Java SE 7 Preview presentations I’m doing on the No Fluff tour in Reston, VA and Chicago, IL. I worked up some JSR 203 (the new new I/O JSR) examples and thought I would drop them here in case they were useful. These are based on the latest Javadocs available on the project page (b97).
I’m not putting much context here. You can read a well written summary from Elliotte Rusty Harold or watch the JavaOne presentation. Or come see my talks. :)
I actually did a talk like this about 18 months ago and went back and looked at it and the API has changed a lot since then. In many ways, it’s been simplified and consolidated much to its overall benefit. In just the last few months, there’s been a lot of polishing, especially making better use of enums and little things like that. Some of those changes are good and some are pretty long-winded in use.
Path is the new File. It’s a little more nuanced than that, but Path is definitely the center of the new filesystem API. Here’s some basic fiddling with it: [source:java]
import java.nio.file.*;</p>
// FileSystems -> FileSystem -> Path
FileSystem fileSystem = FileSystems.getDefault();
Path homeDir = fileSystem.getPath(“/Users/amiller”);
// Shortcut with Paths helper class
Path homeDir = Paths.get(“/Users/amiller”);
// Resolve one path in terms of another
Path relativeTemp = Paths.get(“temp”);
Path absoluteTemp = relativeTemp.resolve(homeDir);
// Get relative path from a base
Path absoluteProfile = Paths.get(“/Users/amiller/.profile”);
Path relativeProfile = absoluteProfile.relativize(homeDir);
assert relativeProfile.isRelative();
assert relativeProfile.getNameCount() == 1;
[/source]
And here’s an example of opening and appending to a file:
[source:java]
import java.io.*;
import java.nio.file.*;
import static java.nio.file.StandardOpenOption.*;
Path journal = Paths.get(“/Users/amiller/journal.txt”);
OutputStream stream = journal.newOutputStream(CREATE, APPEND);
try {
writeEntry(stream); // normal stuff
} finally {
stream.close();
}
[/source]
One nice thing is that copy and move are built-in (at long, long last):
[source:java]
import java.nio.file.*;
Path home = Paths.get(“/Users/amiller”);
Path secrets = home.resolve(“secrets.txt”);
// Steal secrets
secrets.copyTo(home.resolve(“stolenSecrets.txt”));
// Hide secrets
secrets.moveTo(Paths.get(“/Users/dvader/secrets.txt”));
[/source]
There is lots of support now for walking directories – here are some internal and external iterator versions:
[source:java]
Path music = Paths.get(“/Users/amiller/files/music”);
// External iterator
DirectoryStream
try {
for(Path entry : mp3s)
System.out.println(entry.getName());
} finally {
mp3s.close();
}
// Internal iterator
Files.withDirectory(music, “*.mp3”, new FileAction
public void invoke(Path entry) {
System.out.println(entry.getName());
}
}
[/source]
And there is even a visitor pattern for walking a directory recursively (with support for following symbolic links, checking for cycles, etc):
[source:java]
Path itunes = Paths.get(“/Users/amiller/Music/iTunes/iTunes Music”);
public class Mp3Visitor extends SimpleFileVisitor
private Path root;
public Mp3Visitor(Path root) {
this.root = root;
}
public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) {
System.out.println(root.relativize(file));
}
}
Files.walkFileTree(itunes, new Mp3Visitor(itunes));
[/source]
And of course, we also finally have support for accessing posix file attributes as part of the API (and some other common attribute sets and extensible support for other pluggable file systems):
[source:java]
Path file = Paths.get(“/usr/bin/perl”);
// true here means follow symbolic links
BasicFileAttributes attrs =
Attributes.readPosixFileAttributes(file, true);
Set
System.out.format(“%s %s %s”, PosixFilePermission.toString(attrs.permissions()), attrs.owner(), attrs.group());
// rwxr-xr-x root wheel
[/source]
Finally, there is now support for generic “watch services” to watch file events in a directory (with efficient support depending on the platform): [source:java]
import static java.nio.file.StandardWatchEventKind.*;
Path deploy = Paths.get(“deploy”);
WatchService watcher = FileSystems.getDefault().newWatchService();
WatchKey key = deploy.register(watcher, ENTRY_CREATE, ENTRY_DELETE, ENTRY_MODIFY } );
for(;;) {
key = watcher.take(); // blocks, also can poll
for(WatchEvent<?> ev : key.pollEvents()) {
switch(event.kind()) {
case ENTRY_CREATE:
Path file = (Path)ev.getContext(); //relative to deploy
// deploy new stuff
case ENTRY_MODIFY: …
case ENTRY_DELETE: …
}
}
key.reset(); // reset after processing
}
[/source]
If anyone spots any bugs, please let me know.