More on Java 7 File IO
A reader of my previous blog on Java SE 7's File IO enhancements asked how symbolic links are handled in an OS-agnostic way. Good question! Let's examine that now. Recall Java 7's new Path class, and how it abstracts the details of the path to a directory or file, as in this example:
Path path = FileSystems.getDefault().getPath(".", name); InputStream in = Files.newInputStream(path); BufferedReader reader = new BufferedReader(new InputStreamReader(in)); List<String> lines = new ArrayList<>(); String line = null; while ( (line = reader.readLine()) != null ) lines.add(line); // ...
What my summary left out is that the class
Path represents not only files and directories, but links to files and directories, symbolic or otherwise. In fact, the
Path class detects and handles links automatically, without requiring you to do anything specific when one is encountered in your application. However, you do have options available on how to handle symbolic links when they occur, and you can also create new links in Java for file systems that support them.
Soft or Hard Link?
Like ice-cream, links come in two main varieties: soft (or symbolic) and hard. What's the difference? Symbolic links refer to other files or directories and are generally transparent to applications that use them. They are simply pointers to actual files. Operating systems are usually very lenient with how they are created and used, and therefore problems can arise. One example is a symbolic link that forms a circular reference: An application that recursively walks a directory tree that contains a symbolic link that points back to a higher level in the very same tree will recurse infinitely.
A hard link is more restrictive, and often resolves many of the issues related to soft links. However, because of these restrictions, they are generally used less often than soft links. Hard links have the following restrictions:
- The target of the link must exist
- The target cannot be a directory
- The target must exist on the same partition or volume
Java SE 7 and Links
The Java 7
Files classes work with both soft (symbolic) and hard links. For example, to determine if a
Path is a symbolic link, you pass it to the
// links to /logs/myapplogs/myapplog Path logs = FileSystems.getDefault().getPath("~/MyApp/MyAppLog"); boolean isSoftLink = Files.isSymbolicLink(logs);
To resolve a symbolic link, read the output (yet another
Path object) of a call to
Files.readSymbolicLink(), where the
Path object representing the link is passed as a parameter:
Path target = Files.readSymbolicLink(logs); System.out.println("MyApp log file resides here: " + target.toString() );
To create a symbolic link (not supported on Windows), you use the aptly named
Files.createSymbolicLink() method, and pass two
Path objects. The first represents the link to be created, and the second is the path to the actual target file or directory:
// the link to be created Path link = FileSystems.getDefault().getPath("~/MyApp/MyAppLog"); // the target file (doesn't really need to exist) Path target = FileSystems.getDefault().getPath("/logs/myapplogs/myapplog"); Files.createSymbolicLink(link, target);
You can create a hard link (which is supported by Windows) but the target file must exist in this case:
// the link to be created Path hardLink = FileSystems.getDefault().getPath("/Program Files/MyApp/MyAppLog"); // the target file (MUST EXIST!!) Path target = FileSystems.getDefault().getPath("/WINDOWS/Temp/myapplogs/myapplog"); Files.createLink(hardLink, target);
In any of these examples, if the underlying OS does not support symbolic and/or hard links, or if you violate one of the restrictions of hard links, you will get an
IOException at runtime. Therefore, be ready to handle this situation gracefully in your code.
Diving deeper into Java SE 7's File IO APIs, you can use the
FileVisitor interface to determine if and how links are followed, when to avoid them (i.e. when deleting files), and detect if a circular reference exists.