NIO.2 : The new Path API in Java 7

Java Logo

In Java 7 we’ll see a new API to manipulate file paths. This is part of the NIO.2 API.

Instead of using the class java.io.File to manipulate a file of the file system of the computer we will now use the java.nio.file.Path class to manipulate a file in any file system (FileSystem). This FileSystem can use any storage place (FileStorage). To support several implementations, this new API is based on factories. With that, you doesn’t have to care about the real implementation.

A little example to start : In Java < 7, you do that :

File file = new File("index.html");

and with Java 7, you can do that :

Path path = Paths.get("index.html");

To make the migration easier, the File class has a new method toPath() that allows you to transform File to Path :

Path path = new File("index.html").toPath();

But, it’s only useful for migration purpose, we will not use that normally.

By default, all the Path will refers to files in the basic file system (the file system of the computer), but this new API is totally modular. We could imagine an implementation of FileSystem for data in memory, on the network or a virtual file system.

Like File, a Path can also refer to a not existing file. That’s only file path, not the data containing in a file.

If we look at the methods of this new class, we can see that we have almost the same methods than the File class. But there is an important difference. The methods of the Path class throws Exception and that’s a really good points. In fact, with the old File methods, we doesn’t know anything if there is a problem. Sometimes we know that a problem occured with a simple boolean, but that’s all.

Now we can have the cause of the Exception, that’s far better. Here is a little example to delete a file using File :

if (!file.delete()){
    //What happens ?
}

and now using Path :

try {      
    path.delete();    
} catch (IOException e) {
    // We can know the cause and have a good reaction
}

An other enormous difference is the access to the attributes of the denoted file. In the old style, we have only access to the properties available in all the operating system. Now with views we can access the basic views, existing for all the operating systems and more specific views (DOS and POSIX) for properties available only in certain operating systems.

Here is a little example to get the basic attributes of a Path :

BasicFileAttributeView basicView = path.getFileAttributeView(BasicFileAttributeView.class, LinkOption.NOFOLLOW_LINKS); 
 
//This attribute view is perhaps not available in this system
if (basicView != null) {
    BasicFileAttributes basic = basicView.readAttributes(); //Get the attributes of the view
 
    System.out.println("Path refers to a regular file : " + basic.isRegularFile());
    System.out.println("Path refers to a directory : " + basic.isDirectory());
    System.out.println("Path refers to a symbolic link : " + basic.isSymbolicLink());
    System.out.println("Path refers to a file with a size of : " + basic.size());
    System.out.println("Path refers to a file last created at : " + basic.creationTime());
    System.out.println("Path refers to a file last accessed at : " + basic.lastAccessTime());
    System.out.println("Path refers to a file last modified at  : " + basic.lastModifiedTime());
}

This methods can return null if the attribute is not supported. We can also do that for the DOS attributes :

DosFileAttributeView dosView = path.getFileAttributeView(DosFileAttributeView.class); 
 
//This attribute view is perhaps not available in this system
if (dosView != null) {
    DosFileAttributes dos = dosView.readAttributes(); //Get the attributes of the view
 
    System.out.println("Path refers to a hidden file : " + dos .isHidden());
    System.out.println("Path refers to a read only file : " + dos .isReadOnly());
    System.out.println("Path refers to a system file: " + dos .isSystem());
    System.out.println("Path refers to an archive file : " + dos .isArchive());
}

You’re really lucky if that works in Unix ;)

All the DOS and POSIX implementations extends the Basic view, so you can access all the basic attributes from an implementation view.

To make easier, there is also static methods in the Attributes class to access the attributes. By example :

BasicFileAttributes basic = Attributes.readBasicFileAttributes(path);

In the other functionalities, we can note that this new API supports symbolic links (only if the system supports them, of course). Next, the Path class has also flows factories methods like newInputStream() or newByteChannel() to easily create streams to or from the Path. That’s also an advantage because the system can choose the good stream implementations to open depending on the system specifications.

An other facility offered by Path, is stream on directories. It seems that you can iterate through a directory with an iterator. That’s better than File.listFiles() because not all the File are loaded in memory and that’s also a bit clearer in code :

DirectoryStream directory = path.newDirectoryStream(); 
 
try {
    for (Path p : directory) {
        System.out.println(p);
    }
} finally {
    directory.close();
}

And last, but not least, you can now watch for modifications in a directory with WatchService :

WatchService watcher = path.getFileSystem().newWatchService(); 
 
path.register(watcher,
      StandardWatchEventKind.ENTRY_CREATE,
      StandardWatchEventKind.ENTRY_MODIFY,
      StandardWatchEventKind.ENTRY_DELETE); 
 
while (true) {
    WatchKey watchKey = watcher.take(); 
 
    for (WatchEvent event : watchKey .pollEvents()) {
        System.out.println(event.kind() + " : " + event.context());
    } 
 
    watchKey .reset();
}

That will use the services offered by the operating system (Notification, inotify, FSEvents). This is really easier than writing native code to do that, isn’t it ?

Here we are. We’ve covered the main functionalities of the new Path API in Java 7.

I hope you find this article interesting and that helped you discovering the new features of Java 7.

Related posts:

  1. Do not use relative path with LogBack
  2. Java File Copy Benchmark Updates (once again)
  3. Tip : Profile an OSGi application with VisualVM
  4. Develop a modular application – Implementation
  5. Java 7 : New I/O features (Asynchronous operations, multicasting, random access) with JSR 203 (NIO.2)
  • soma

    This is nice. Gave me the first lessons of NIO in JDK 7. thanks

  • soma

    This is nice. Gave me the first lessons of NIO in JDK 7. thanks

  • jawed

    very interesting features…

  • jawed

    very interesting features…

  • http://www.west.nl Gertjan van Oosten

    The line

    BasicFileAttributeView basicView = path.getFileAttributeView(BasicFileAttributeView.class);

    should be

    BasicFileAttributeView basicView = path.getFileAttributeView(BasicFileAttributeView.class, LinkOption.NOFOLLOW_LINKS);

    otherwise

    System.out.println(“Path refers to a symbolic link : ” + basic.isSymbolicLink());

    will always print ‘false’ (and the other printed values might also be incorrect since they would be of the symlinked-to path if path were a symlink).

    • Baptiste Wicht

      Yes, you are right :)

      I forgot that, Thanks.

  • http://www.west.nl Gertjan van Oosten

    The line

    BasicFileAttributeView basicView = path.getFileAttributeView(BasicFileAttributeView.class);

    should be

    BasicFileAttributeView basicView = path.getFileAttributeView(BasicFileAttributeView.class, LinkOption.NOFOLLOW_LINKS);

    otherwise

    System.out.println(“Path refers to a symbolic link : ” + basic.isSymbolicLink());

    will always print ‘false’ (and the other printed values might also be incorrect since they would be of the symlinked-to path if path were a symlink).

    • Baptiste Wicht

      Yes, you are right :)

      I forgot that, Thanks.

  • Aurelian Tutuianu

    Really helpful to get an idea of this part of JDK7. Many thanks.

  • Aurelian Tutuianu

    Really helpful to get an idea of this part of JDK7. Many thanks.

  • Geoffrey De Smet

    The delete() method throws IOException, not a RuntimeException. Why prefer a (un)checked exception over the other?

    • Baptiste Wicht

      Sorry, but where dit i talk about RuntimeException, in my code, i catch IOException.

  • Geoffrey De Smet

    The delete() method throws IOException, not a RuntimeException. Why prefer a (un)checked exception over the other?

    • Baptiste Wicht

      Sorry, but where dit i talk about RuntimeException, in my code, i catch IOException.

  • http://dhruba.name Dhruba Bandopadhyay

    This is an interesting area of jdk7 indeed and one that I’m looking forward to. FYI I’ve also done a comprehensive write-up on this topic some time back. It would also be nice to see a further write-up on asynchronous IO, socket operations and multicast datagrams in jdk7. I intend to do this myself at some point.

  • http://dhruba.name Dhruba Bandopadhyay

    This is an interesting area of jdk7 indeed and one that I’m looking forward to. FYI I’ve also done a comprehensive write-up on this topic some time back. It would also be nice to see a further write-up on asynchronous IO, socket operations and multicast datagrams in jdk7. I intend to do this myself at some point.

  • Pingback: Blog harvest, March/Easter 2010 « Schneide Blog

  • Roman

    Why not callback (or even closure) instead of this:

    while (true) {
    WatchKey watchKey = watcher.take();

    for (WatchEvent event : watchKey .pollEvents()) {
    System.out.println(event.kind() + ” : ” + event.context());
    }

    watchKey .reset();
    }

    ?

    • Baptiste Wicht

      I don’t know :(

      Perhaps that could change. It will be fine with closure, but like these lasts are not completely implemented perhaps it’s only a draft before closure. Wait and see :)

  • Roman

    Why not callback (or even closure) instead of this:

    while (true) {
    WatchKey watchKey = watcher.take();

    for (WatchEvent event : watchKey .pollEvents()) {
    System.out.println(event.kind() + ” : ” + event.context());
    }

    watchKey .reset();
    }

    ?

    • Baptiste Wicht

      I don’t know :(

      Perhaps that could change. It will be fine with closure, but like these lasts are not completely implemented perhaps it’s only a draft before closure. Wait and see :)

  • Magaly Friesen

    Thank you so much!!!!

    http://driver-assist.info

  • http://www.sandtheater.com vanyatka

    How come NIO2 will be using checked exceptions?? Unbelievable.