Working with PathsEdit

A Path is java.nio.file's equivalent of a File. Just like a File, a Path is an abstract representation of a filesystem object; unlike a File, however, a Path can represent a resource not on your hard drive.

In a similar fashion to File as well, creating a Path does not mean that there is a filesystem object at that path.

Getting Paths Edit

Since java.nio.file supports multiple filesystems (and their path implementation differs), you need a filesystem to get your paths from. And the JRE provides a default filesystem (which implementation depends on your operating system).

In order to get a path from your default filesystem, you will use Paths.get() as in, for instance:

Paths.get("someFileName"); // get a path relative to the JVM's current working directory
Paths.get("first/elements", "second/elements", "etc", "etc"); // "composite" path

Invoking Paths.get() is in fact exactly equivalent to:

FileSystems.getDefault().getPath("someFileName"); // like above
FileSystems.getDefault().getPath("first/elements", "second/elements", "etc", "etc"); // like above

From File to Path; and the reverse Edit

If you have a File, you can get a Path from it: File.toPath().

The reverse is also possible, but please only use it when you have no choice! This is Path.toFile(). However, the latter will only work if the Path is issued from the default filesystem!

Manipulating paths Edit

The Path class also offers a lot of manipulation methods. For instance:

 * Resolving one path against another. For instance, if path is /foo/bar and other is baz,
 * the result will be /foo/bar/baz.
final Path resolved = path.resolve(otherPath);
 * Resolving a sibling. Here, if path is /foo/bar, the result is /foo/baz.
final Path sibling = path.resolveSibling("baz");
 * Normalizing a path. This removes all redundant name components of the path,
 * typically "." (self) and ".." (parent).
 * If path is /foo/./bar/baz/.., the result will be /foo/bar.
final Path normalized = path.normalize();
 * Get an absolute path; this will NOT resolve symbolic links:
final Path absolute = path.toAbsolutePath();
 * But this will:
final Path real = path.toRealPath();
 * Relativize; if path is /foo/bar/baz and other is /foo/bar/hello, the result will be
 * "../hello":
final Path relativized = path.relativize(other);

And there are others. Refer to the javadoc for more details.

Note about resolution/relativization: these methods will not perform path normalization for you; you need to normalize yourself.

Opening files Edit

First and foremost: try-with-resources Edit

This new construct which appeared in Java 7 allows you to safely open and close resources. It applies to any class implementing the AutoCloseable interface.

And this include everything Closeable, so your classical InputStreams, PreparedStatements and others can use it. The syntax is:

try (
    // initialize your resources here
) {
    // do something with your resources here

Note that exceptions are still thrown, either from the try block or closing failure. The exception thrown, if any, will be the first to be seen by user code, either from the try block or from the first resource which failed to close properly; all other exceptions other than the first will be suppressed, but if you want (or need to), you can still access them.

Streams and channels Edit

This same Files class also contains methods you will use to open files. You can obtain "classical" {Input,Output}Streams or NIO Channels (for reading bytes), and also Readers and Writers (for reading text):

To read a text file and process every line in it, for instance, we will use:

// "path" is the path to our text file
try (
    final BufferedReader reader = Files.newBufferedReader(path, StandardCharsets.UTF_8);
    // You can open other resources if needed
) {
    String line;
    while ((line = reader.readLine()) != null) {
        // work with line

More... Edit

Note: Stream also implements Autocloseable! That means you can also use a Stream in a try-with-resources statement, and while that does not make much sense for streams not bound to I/O, it does make sense to use it for those who are; and Files.lines() is one of these! Therefore you will want to write:

try (
    final Stream<String> stream = Files.lines(myPath, StandardCharsets.UTF_8);
) {
    stream.forEach(System.out::println); // very simple consumer

Copying, deleting and moving Edit

Copying Edit

The Files class has three different copy methods:

The first and last methods accept a set of copy options; for instance, you can tell to replace the existing file, if any, when you copy from a path to another:

Files.copy(source, destination, StandardCopyOption.REPLACE_EXISTING);

Note that this method will not perform recursive copies.

Deleting Edit

There are two methods to delete: Files.delete() and Files.deleteIfExists().

Note that they will not perform recursive deletions.

Moving Edit

The method to do this is Files.move().

Note that it will not do recursive moving across filesystems! If you attempt to move a non empty directory to a destination which is not on the same filesystem, you will get a DirectoryNotEmptyException. Similarly, if you select to replace the destination, it will not remove a non empty directory.

Directories and trees Edit

The API also provides a way to walk (and filter) the entries in a directory, but also the API to walk an entire file tree.

Directories Edit

The basic method to walk the entries of a directory is Files.newDirectoryStream(). It will return a DirectoryStream, which implement both Iterable and Closeable; the preferred usage is therefore to use it in a try-wit-resources block, as in:

try (
    final DirectoryStream<Path> dirstream = Files.newDirectoryStream(dirpath);
) {
    for (final Path entry: dirStream) {
        // work with entry
} // directory stream closed here

There are two other versions of this method: one taking a full-blown filter as an argument and one taking a glob string as an argument. This means you can do this:

try (
   final DirectoryStream<Path> dirstream = Files.newDirectoryStream(dirpath, "*.txt");
) // etc etc

Note that if for one reason or another the walk is interrupted, a DirectoryIteratorException is thrown, and this exception is unchecked; if you want to capture it, you therefore have to do so explicitly. The exception which caused the iteration exception to occur will be available using .getCause().

With Java 8, you also have Files.list(). You also want to use it in a try-with-resources statement!

Trees Edit

The old API didn't provide any facility for walking entire file trees; the new one does, however its use is a little demanding... Except if you use Java 8.

IMPORTANT!: please note that the default behavior of all methods below is to NOT follow symbolic links.

With Java 7 you have Files.walkFileTree(). It requires that you provide it with a FileVisitor that you have to write yourself... Fortunately you do have a base implementation which you can extend instead of directly implementing the interface.

With Java 8, things change: Files.walk() has appeared. It returns a Stream<Path>. Similarly, use this stream in a try-with-resources statement!.

Note! Before you try and .filter() such a stream, be aware that there is also Files.find() which can do that for you...

Metadata Edit

The java.nio.file API offers a very complete API for querying metadata on filesystem objects. Information which was previously inaccessible to the language (such as "who" owns the file, what are its permissions etc) is now available, and modifiable.

Basic metadata Edit

In the vast majority of cases, what you will use to manipulate your paths is the Files class.

This class has a lot of methods, and we will start by listing the ones which perform basic checks:

Other, basic information (such as the size, for instance) is available using simple methods. Please refer to the javadoc for more information.

Note: some methods above accept a LinkOption as an argument. In fact, there is only one such option currently defined: LinkOption.NOFOLLOW_LINKS. By default, symbolic links are followed.

Note 2: LinkOption implements both CopyOption and OpenOption. As a consequence, you may pass this option to any method which accepts either (useful for copies if you want to copy the link itself but not the pointed entry, for instance).

"Unix" metadata Edit

The Files class also provides methods to query/set classical Unix metadata on files, starting with its permissions. Here is for example how you would set the permissions on a file to 0644:

final Set<PosixFilePermission> perms = PosixFilePermissions.fromString("rw-r--r--");
Files.setPosixFilePermissions(target, perms);

Similarly, you can query permissions on a path with Files.getPosixFilePermissions().

You can also query or set the last modified time of a file. Here is how to get the last modified time:

final FileTime lastModified = Files.getLastModifiedTime(thepath);

You also have the possibility to query the owner and group of a file system object:

final UserPrincipal user = Files.getOwner(thepath);

You can even set the owner of a file! However, you don't run your Java applications as a user which can do that, do you? ;)


Much more can be done with metadata. If you are interested, see this page.

Using the zip filesystem providerEdit

At least with OpenJDK, and therefore with the Oracle JDK, you have a zip filesystem provider included.

This means you can use the API to manipulate the contents of a zip file (this of course includes jars and wars) as you do the contents of your hard drive (the default file system).

Example: Creating a zipEdit

The scheme associated with zip files is jar. That is quite bizarre, but that's the way it is.

Here is how you would create a zip file:

// Get a path to the zip file you want to create as a URI
// Here we pick a file in the temporary directory
final String zipPath = Paths.get(System.getProperty(""), "");

// Now that we have this, create the URI
final URI zipUri = URI.create("jar:" + zipPath.toUri());

// And now the filesystem settings; we want to create a new zip file, therefore:
final Map<String, String> env = Collections.singletonMap("create", "true");

// Now create the filesystem!
try (
     final FileSystem zipfs = FileSystems.newFileSystem(zipUri, env);
) {
    // Copy one file from our filesystem to the zip we just created
    final Path src = Paths.get("some/file/somewhere");
    final Path dst = zipfs.getPath("nameInZip");

    Files.copy(src, dst);
    // Other...
} // Filesystem closed here; zip created!