NIO.2 : The new Path API in Java 7
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.
Comments
Comments powered by Disqus