Pure Danger Tech


Some JSR 203 Examples

22 Oct 2008

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;


And here’s an example of opening and appending to a file:


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 {




One nice thing is that copy and move are built-in (at long, long last):


import java.nio.file.*;

Path home = Paths.get(“/Users/amiller”);

Path secrets = home.resolve(“secrets.txt”);

// Steal secrets


// Hide secrets



There is lots of support now for walking directories – here are some internal and external iterator versions:


Path music = Paths.get(“/Users/amiller/files/music”);

// External iterator

DirectoryStream mp3s = music.newDirectoryStream(“*.mp3”);

try {

for(Path entry : mp3s)


} finally {



// Internal iterator

Files.withDirectory(music, “*.mp3”, new FileAction() {

public void invoke(Path entry) {





And there is even a visitor pattern for walking a directory recursively (with support for following symbolic links, checking for cycles, etc):


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) {




Files.walkFileTree(itunes, new Mp3Visitor(itunes));


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):


Path file = Paths.get(“/usr/bin/perl”);

// true here means follow symbolic links

BasicFileAttributes attrs =

Attributes.readPosixFileAttributes(file, true);

Set perms = attrs.permissions();

System.out.format(“%s %s %s”, PosixFilePermission.toString(attrs.permissions()), attrs.owner(), attrs.group());

// rwxr-xr-x root wheel


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()) {


Path file = (Path)ev.getContext(); //relative to deploy

// deploy new stuff





key.reset(); // reset after processing



If anyone spots any bugs, please let me know.