Saturday, August 6th, 2011

File I/O and File Attributes in Java 7

A previous post introduced the filestat package for accessing low-level file attributes from Java on a Unix/Linux platform. The recently released Java 7 includes functionality for doing that job and a lot more.

Up to recently some file operations in Java required native methods. To a true geek adding native methods just means adding to the fun. But even a geek must admit native code solves problems by creating new ones. Portability is lost.

In Java 7 two packages have been added for file I/O: java.nio.file and java.nio.file.attribute. The new functionality is sometimes referred to as "nio.2". The main classes are java.nio.file.Files and java.nio.file.Path. With their auxiliary classes they provide a thoroughly revised, comprehensive and portable Java interface to file systems.

The new file I/O is based on a service provider concept, like several other parts of Java. You may customize a file system view of any resource of your choice, a database for instance. What you must do is implement the classes of the java.nio.file.spi package. The release documents indicate that a fully supported file system view of zip and jar files is available. At the time of writing I just can't find it.

With the default provider a new Path may be converted to a plain old java.io.File through its toFile() method. Inversely, java.io.File now has a toPath() method.

Here is sample code exercising some of the new functionality.

JAVA:

  1. import java.io.IOException;
  2. import java.nio.file.DirectoryStream;
  3. import java.nio.file.FileSystems;
  4. import java.nio.file.Files;
  5. import java.nio.file.Path;
  6. import java.nio.file.attribute.PosixFileAttributes;
  7. import java.nio.file.attribute.PosixFileAttributeView;
  8. import java.nio.file.attribute.PosixFilePermission;
  9. import java.util.Set;
  10.  
  11. public class FileAttrs {
  12.     private final Path topDir;
  13.  
  14.     public FileAttrs(String topDirName) {
  15.     topDir = FileSystems.getDefault().getPath(topDirName);
  16.     }
  17.  
  18.     public static void main(String[] args) {
  19.     if (args.length> 0) {
  20.         try {
  21.         FileAttrs attrs = new FileAttrs(args[0]);
  22.         attrs.scan();
  23.         } catch (Exception exc) {
  24.         System.err.println("Oops! " + exc);
  25.         }
  26.     } else {
  27.         System.err.println("Directory name required");
  28.     }
  29.     }
  30.  
  31.     public void scan() throws IOException {
  32.     DirectoryStream<Path> dirStream = Files.newDirectoryStream(topDir);
  33.     int symlinkCount = 0;
  34.     int writableCount = 0;
  35.     for (Path path : dirStream) {
  36.         if (Files.isSymbolicLink(path)) {
  37.         symlinkCount++;
  38.         } else {
  39.         PosixFileAttributeView view = Files.getFileAttributeView(path, PosixFileAttributeView.class);
  40.         if (view == null) throw new UnsupportedOperationException("Posix file attribute view not available");
  41.         PosixFileAttributes attrs = view.readAttributes();
  42.         Set<PosixFilePermission> perms = attrs.permissions();
  43.         if (perms.contains(PosixFilePermission.GROUP_WRITE) ||
  44.             perms.contains(PosixFilePermission.OTHERS_WRITE)) {
  45.             writableCount++;
  46.         }
  47.         }
  48.     }
  49.  
  50.     System.out.println(topDir + ": symlinks " + symlinkCount +
  51.                ", writable by group or others " + writableCount);
  52.     }
  53. }

Given the name of a directory this program counts the number of symbolic links in the directory and the number of non-symlink files writable by group or others. It's Java so it must be fully portable, isn't it?

Portability in this case means you can compile and run the program on any platform. However, there is meaningful output only if it is run on a Posix file system. The crucial point is line 39. The method getFileAttributeView() may return null. This happens if you run the program on a Windows platform because there is no Posix view of the file system.

In my opinion the new file I/O seems useful and well designed. As usual when returning to Java from Groovy the code appears quite verbose. It is actually possible to get the Posix file attributes with less keystrokes by Files.getPosixFilePermissions(). However, that method throws an exception if the Posix file view is not available, so a try-catch is also needed.

Comments are closed.