Java Basics: NIO Files

Exploring the NIO File package

As promised, here’s a Java Basics post covering the java.nio.file package.  We’ll mostly be exercising the Files class, but in doing that we’ll also be using FileSystems, FileSystem and Path.

The N in NIO stands for Non-blocking. The nio.file package was added in Java 7.  It’s meant to provide extended functionality for working with file systems.  It can handle symbolic/hard links for example.

We’ll start by looking at some of the information we can get about a file or directory using the Files class.  Then we’ll take a quick look at the walk functionality.  From there we’ll read, write and copy files.

Getting File or Directory Information

A lot of the information we’ll be getting using the Files class can also be gotten using java.io.File, so let’s first go over the difference between Files and File.  A File represents a single file or directory and allows us to operate on it.  The Files class is an abstract class that provides static methods for working on the file system.

The methods in the Files class often takes one or more Path objects.  Path objects generally point to a file or directory in the file system. The first thing our method that demonstrates Files functionality does is get a Path to our example text file.  To get the Path, we using the FileSystems factory class to get the default FileSystem and then get the path using our file name.

For our example, it’s equivalent to doing this:

Path path = Paths.get(TEXT_FILE_NAME);

The usage of the methods is mostly self-explanatory, so we’ll just take a quick look at several of the informational methods available.

public void displayFileInformation() throws IOException {
   Path path = FileSystems.getDefault().getPath(TEXT_FILE_NAME);
   System.out.printf("Does file %s exist? %b\n", TEXT_FILE_NAME, Files.exists(path));
   System.out.printf("Does file %s not exist? %b\n", TEXT_FILE_NAME, Files.notExists(path));
   System.out.printf("Is %s a directory? %b\n", TEXT_FILE_NAME, Files.isDirectory(path));
   System.out.printf("Is %s a regular file? %b\n", TEXT_FILE_NAME, Files.isRegularFile(path));
   System.out.printf("%s permissions (rwx): %b %b %b\n", TEXT_FILE_NAME, Files.isReadable(path), Files.isWritable(path), Files.isExecutable(path));
   FileTime lastModifiedTime = Files.getLastModifiedTime(path);
   System.out.printf("%s was last modified on %s\n", TEXT_FILE_NAME, new java.util.Date(lastModifiedTime.toMillis()).toString());
   System.out.printf("Size of %s: %d bytes\n", TEXT_FILE_NAME, Files.size(path));
   System.out.printf("%s content type is %s\n", TEXT_FILE_NAME, Files.probeContentType(path));
   System.out.printf("%s content type is %s\n", JPG_FILE_NAME, Files.probeContentType(FileSystems.getDefault().getPath(JPG_FILE_NAME)));
}

Walking

The Files class provides a simple way to “walk” the directory tree from a given starting Path.  For our example, we’ll create a Path to our project directory and just print out the Path objects we walk through.

public void walk() throws IOException {
   Path path = FileSystems.getDefault().getPath(PROJECT_DIR);
   Files.walk(path).forEach(System.out::println);
}

Reading

The Files class provides several ways to read from a file.  First off, we’ll create a Path to our example text file.

Path path = FileSystems.getDefault().getPath(TEXT_FILE_NAME);

The first way to read a text file is the lines method which returns a Stream of String from the file.  Note that we retrieve our lines within a try-with-resources block.

try (Stream<String> lines = Files.lines(path)) {
   lines.forEach(System.out::println);
}

Similarly, the readAllLines method returns a List of String containing the lines of the file.

Files.readAllLines(path).stream().forEach(System.out::println);

We can also get a BufferedReader for a given Path and use that.  This might be especially handy if we’re calling an existing method that takes a Reader.  Note the try-with-resources.

try (BufferedReader br = Files.newBufferedReader(path)) {
   String line = "";
   while ((line = br.readLine()) != null) {
      System.out.println(line);
   }
}

Now we’re going to look at some byte oriented options, so we’ll create a Path to our example jpg file.

Path binPath = FileSystems.getDefault().getPath(JPG_FILE_NAME);

The binary file equivalent to readAllLines is readAllBytes and we can use that to grab all the bytes in a file.

byte[] coffeeBytes = Files.readAllBytes(binPath);

We can also get an InputStream that we might use for a more controlled read or pass to an existing method that requires one.

try (InputStream is = Files.newInputStream(binPath)) {
   byte[] input = new byte[1024];
   int counter = 0;
   while (is.read(input) >= 0) {
      //Normally we'd do some useful work on our input bytes
      counter++;
   }
   System.out.printf("Binary file %s contains %d bytes\n", JPG_FILE_NAME, coffeeBytes.length);
}

Writing

As with reading, the Files class provides convenient ways of writing a file.  We’ll start by defining a path to our output text file.  This should be pretty predictable by now.

Path path = FileSystems.getDefault().getPath(OUT_FILE_NAME);

One way to write a bunch of lines to a file is to create a collection of lines and pass it to the write method along with the Path.  The write methods take an optional parameter for specifying OpenOptions.  This will overwrite any existing data because we left it off.

List<String> lines = new ArrayList<String>();
lines.add("This is a line of text.");
lines.add("This is another line of uninspired text.");
lines.add("I could go on...");
      
Files.write(path, lines);

We can also call the write method with an array of bytes.  Typically this will be used for binary data, but we’re going to use it to write another string to our file.  Since we want to append, we’ll also be demonstrating using StandardOpenOption.APPEND.

String text = "This is a line to append";
Files.write(path, text.getBytes(), StandardOpenOption.APPEND);

Similarly to BufferedReader, we can also get a BufferedWriter.  We’re going to get our BufferedWriter in append mode too.  We won’t see an example for it here, but we can also get an OutputStream using newOutputStream.  Again, note the try-with-resources.

try (BufferedWriter bw = Files.newBufferedWriter(path, StandardOpenOption.APPEND)) {
   bw.write("This line was appended using a BufferedWriter retrieved from Files");
}

Copying

In the Java Basics: File I/O, I ended with an example of a file copy utility, so let’s wrap up here by taking a look at the copy functionality in the Files class.

We’ll copy both a text file and a binary file, so let’s first create Path objects to our source and destination files.  Our destination file will be created if it doesn’t exist.

Path textSource = FileSystems.getDefault().getPath(TEXT_FILE_NAME);
Path textDest = FileSystems.getDefault().getPath(COPY_TEXT_NAME);

Once we have our Path objects, we simply call the copy method.  We provide both paths and also StandardCopyOption.REPLACE_EXISTING which does exactly what it sounds like it does.

Path targetText = Files.copy(textSource, textDest, StandardCopyOption.REPLACE_EXISTING);

We can also copy binary files in the same way.  Let’s set up our Path objects first.

Path binSource = FileSystems.getDefault().getPath(JPG_FILE_NAME);
Path binDest = FileSystems.getDefault().getPath(COPY_JPG_NAME);

Then we call the copy method.

Path targetBin = Files.copy(binSource, binDest, StandardCopyOption.REPLACE_EXISTING);

Conclusion

In this installment of the Java Basics series, we took a look at the nio.file package in Java.  We mostly focused on the Files class because that’s where a bulk of the functionality is.  I’d like to follow up with an article covering the use of WatchService.

The example code is available on GitHub.

Advertisements

6 thoughts on “Java Basics: NIO Files

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s