Free Online Courses for Software Developers - MrBool
× Please, log in to give us a feedback. Click here to login
×

You must be logged to download. Click here to login

×

MrBool is totally free and you can help us to help the Developers Community around the world

Yes, I'd like to help the MrBool and the Developers Community before download

No, I'd like to download without make the donation

×

MrBool is totally free and you can help us to help the Developers Community around the world

Yes, I'd like to help the MrBool and the Developers Community before download

No, I'd like to download without make the donation

New in Java 7: the NIO.2 API

In this article we will introduce a more complete API for File System Manipulation, the NIO.2 API.

Since its earlier versions, Java was already capable of manipulating files. However, until Java 6 there were several limitations with the API provided by the JVM in package java.io, for instance:
• There is no single operation to copy a file to another location. When necessary, it has to be implemented using data flows (like one of the examples in the previous article in this series);
• Support to file attributes (creation date, last update date, permissions to read/write, executable flag, etc.) is limited;
• It's not 100% consistent throughout the different platforms supported by Java;
• Often, exceptions thrown due to failures during file operations are not very useful;
• It's not possible to extend the API to support a new type of file system.

To address these limitations, JSR 203 – More New I/O APIs for the JavaTM Platform (“NIO.2”) was proposed. This extension was called “NIO.2” because since Java 1.4 the package java.nio is already present, supporting the creation of I/O channels. Channels are objects that represent a connection with a generic resource that is capable of executing I/O operations, such as files and network sockets.
The NIO.2 API adds three subpackages to java.nio:
java.nio.file: main package for NIO.2, defines interfaces and classes to access files and file systems using the new API;
java.nio.file.attribute: contains classes and interfaces related to reading and changing file attributes;
java.nio.file.spi: contains service provider interfaces for NIO.2, to be used by developers who wish the implement support to a new type of file system.

(If you want to learn more about Java, go to our Java online courses)


The following classes (from package java.nio.file) represent the main concepts of the new API:
Path: immutable class that represents the path to any file, like, for instance, /home/vitor/document.odt or C:\Users\Vitor\My Documents\document.doc;
Files: class that contains several static methods for the execution of operations in files given their paths;
FileSystem: class that represents the file system as a whole, used to obtain paths to files;
FileSystems: class that contains several static methods for obtaining a file system. The method FileSystems.getDefault() obtains an object that allows us to access all files to which the JVM has access;
FileStore: class that represents the file storing mechanism that is manipulated by the different methods of the API (a partition of a hard drive, an external device plugged in via USB, etc.).

The new API comes with many new functionalities, addressing the limitations of the old API that have been presented in the beginning of the article. To give an idea of how these new NIO.2 features work, we selected four of them for our demonstrations: glob filtering, file attribute manipulation, recursive navigation in directory trees and event monitoring.

Glob filtering is a pattern matching solution used in command interpreters like the Linux console (e.g., bash) or the Windows command prompt (cmd.exe). In this type of filtering, a question mark (?) represents any single character whereas a star (*) represents any number of characters. These special characters are called wildcards. Now, with NIO.2 it's possible to filter contents in directories using glob filtering, as shown in Listing 1.

Listing 1. Using NIO.2 to list the files with .txt extension and their dates of creation, last access and last update.
package com.mrbool.java7.nio2;

import java.nio.file.*;
import java.nio.file.attribute.*;
import java.text.*;
import java.util.*;

public class ExampleNio2_Attributes {
	public static void main(String[] args) throws Exception {
		FileSystem fs = FileSystems.getDefault();
		
		Properties props = System.getProperties();
		String homePath = props.get("user.home").toString();
		Path home = fs.getPath(homePath);
		
		System.out.println("File\t\t\tCreation Date\t\tLast Access\t\tLast Update");
		try (DirectoryStream<Path> flow = Files.newDirectoryStream(home, "*.txt")) {
			for (Path item : flow) {
				BasicFileAttributes attrs = Files.readAttributes(item, BasicFileAttributes.class);
				Date creationDate = new Date(attrs.creationTime().toMillis());
				Date accessDate = new Date(attrs.lastAccessTime().toMillis());
				Date updateDate = new Date(attrs.lastModifiedTime().toMillis());
				DateFormat df = new SimpleDateFormat("MM/dd/yyyy HH:mm:ss");
				
				System.out.format("%s\t%s\t%s\t%s%n", item, df.format(creationDate), df.format(accessDate), df.format(updateDate));
			}
		}
	}
}


The example starts by obtaining the system property user.home, which contains a string that represents the path to the user's base directory (e.g., /home/vitor in Linux, C:\Users\Vitor in Windows 7, etc.). In case you prefer to use a different directory for this test, just set the homePath variable to the path to the directory you want. For instance, in a Windows system it could be: homePath = "C:\Tests".

The homePath variable is then used to create an instance of class Path, which represents the path to the folder in question. With this object at hand, it's possible to use the methods of the Files class to copy, move, create files/directories/links, delete, check for existence, etc. In the example of Listing 1, however, we use the method Files.newDirectoryStream() to create a flow of information from a directory, which allows us to analyze the files and subdirectories present in that folder. Notice also that:
(a) Glob filtering was used in the creation of the information flow, specifying that it should return only items that end in the .txt extension;
(b) The try with closeable resources feature from Project Coin, presented in an earlier article in this series, was used to automatically close the flow at the end of the block.

With the flow open, it's possible to iterate through it with a for-each loop, manipulating all files with the .txt extension that are inside the given directory. At this point, Listing 1 presents the second feature mentioned earlier: manipulation of file attributes. The method Files.readAttributes() is used to obtain an object of class BasicFileAttributes, which contains basic file attributes that are present in most operating systems: date/time of creation, last access and last update, if the path points to a file, directory, link or other and the size of the file in bytes. Two other interfaces are available to be used in this situation: DosFileAttributes and PosixFileAttributes, with specific attributes for DOS-based systems (i.e., different versions of Windows) and POSIX-based systems (Unix, Linux, MacOS X, among others), respectivelly.

Another feature of NIO.2 demonstrated in this article is the recursive navigation through a tree of directories. Java 7 brings a mini-framework for efficient depth-first navigation given a Path object that represents the starting (root) directory. Listing 2 shows an example. Note that in this example the initial Path object is obtained in a different way than what was done previously in Listing 1: instead of obtaining the default FileSystem, we use the shortcut Paths.get() (highlighted in bold).

Listing 2. Navigating through an entire directory tree with NIO.2.
package com.mrbool.java7.nio2;

import java.io.IOException;
import java.nio.file.*;
import java.nio.file.attribute.BasicFileAttributes;

public class ExampleNio2_Navigating {
	public static void main(String[] args) throws Exception {
		if (args.length != 1) System.out.println("Use: java ExampleNio2_Navigating <directory>");
		Path root = Paths.get(args[0]);
		
		CalculateFileSizeVisitor visitor = new CalculateFileSizeVisitor();
		Files.walkFileTree(root, visitor);
		System.out.format("The given directory contains %d files spred in %d directories, occupying %.4f MB in disk", visitor.numFiles, visitor.numDirs, visitor.sizeSum / (1024.0 * 1024));
	}
}

class CalculateFileSizeVisitor implements FileVisitor<Path> {
	int numFiles = 0;
	int numDirs = 0;
	long sizeSum = 0;
	
	@Override
	public FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes attrs) throws IOException {
		System.out.println("[D] " + dir);
		numDirs++;
		return FileVisitResult.CONTINUE;
	}

	@Override
	public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException {
		System.out.println("[F]\t " + file);
		sizeSum += attrs.size();
		numFiles++;
		return FileVisitResult.CONTINUE;
	}

	@Override
	public FileVisitResult visitFileFailed(Path file, IOException exc) throws IOException {
		System.err.println("It was not possible to analyze the file: " + file);
		return FileVisitResult.TERMINATE;
	}

	@Override
	public FileVisitResult postVisitDirectory(Path dir, IOException exc) throws IOException {
		return FileVisitResult.CONTINUE;
	}
}


To navigate a directory, all we need to use is to call the method Files.walkFileTree(), specifying the Path object that points to the folder to be navigated and an instance of FileVisitor that indicates what should be done to each file and subdirectory found during navigation. For this second parameter, a new class – CalculateFileSizeVisitor – was defined, implementing the required interface.

This new class then overrides the methods defined in the interface, which are called by NIO.2 during the recursive navigation. These methods are:
preVisitDirectory(): executed for each directory found, before its contents are analyzed. Receives as parameter the Path object that points to the folder and an object containing its basic attributes;
visitFile(): executed for each file found. Receives the Path object that represents the file and also an object containing its attributes;
visitFileFailed(): executed in case it's not possible to access a given file (for instance, because you lack the necessary permissions). Receives the Path object that points to the file and an exception (IOException) that indicates the failure that occurred;
postVisitDirectory(): executed for each directory, after its contents were analyzed. Receives the Path object representing the folder and a second parameter that has two possible values: null, in case the processing of the directory occurred without errors, or an exception otherwise.

All four methods should return an instance of FileVisitResult, an enumerated type that defines what to do at the end of the execution of the method:
FileVisitResult.CONTINUE: proceed normally;
FileVisitResult.TERMINATE: interrupt the recursive navigation;
FileVisitResult.SKIP_SUBTREE: if used in the preVisitDirectory() method, continues the navigation but skips the folder currently being analyzed;
FileVisitResult.SKIP_SIBLINGS: continues the navigation, but does not analyze any other files or subdirectories contained in the same folder as the current item (i.e., its siblings).

In the example, the CalculateFileSizeVisitor class calculates the number of existing files and directories and the total size occupied by the files. Furthermore, it prints on standard output each directory ([D]) and file ([F]) analyzed. At the end of the program, the calculated values are also printed.

Finally, the last functionality from NIO.2 presented in this article is the ability of monitoring events from the file system, like creation, update and deletion of files and directories. Listing 3 shows how to monitor for the creation of new files in the user's home directory.

Listing 3. Monitoring file creation events with NIO.2
package com.mrbool.java7.nio2;

import java.nio.file.*;
import java.util.Properties;

public class ExampleNio2_Monitoring {
	public static void main(String[] args) throws Exception {
		FileSystem fs = FileSystems.getDefault();
		WatchService ws = fs.newWatchService();
		
		Properties props = System.getProperties();
		String homePath = props.get("user.home").toString();
		Path home = fs.getPath(homePath);
		
		home.register(ws, StandardWatchEventKinds.ENTRY_CREATE);
		
		System.out.println("Monitoring file creation in " + home + "... (Ctrl+C to quit)");
		while (true) {
			WatchKey key = ws.take();
			for (WatchEvent<?> event : key.pollEvents()) {
				if (event.kind() == StandardWatchEventKinds.ENTRY_CREATE) {
					Path item = (Path)event.context();
					System.out.println("Created: " + item);
				}
			}
			key.reset();
		}
	}
}


First of all, it's necessary to register to the event in question, which is done thought the register() method of the Path object that we intend to monitor (in the example, the variable home). In this method, we should specify a monitoring service (obtained from the FileSystem with the method newWatchService()) and the kind of event to monitor (use one of the static variables present in class StandardWatchEventKinds).

After registering for the event, all we need to do is call the take() method from the monitoring service to block the current thread and wait for some event to happen. Once this occurs, NIO.2 returns from this method with an instance of WatchKey, which can be used to navigate through all the events that occurred while the thread was suspended. Each event contained in this object brings as an attribute the type of event and the file/directory to which the event refers. In the example of Listing 3, every time a file or directory is created in the user's home folder, the program prints the name of the created item on screen.

Putting this code in some kind of loop (the example uses an infinite loop and, therefore, the program should be interrupted with Ctrl+C or will execute indefinitely), you will also need to reset() the WatchKey instance after processing events, otherwise future events will not be sent to the thread.

Beyond the functionalities exemplified in this article, three other characteristics of NIO.2 are worthy of special note:
Support to symbolic links: the API contains a complete support to symbolic links, treating them as if they were the file or directory to which they refer. As a consequence, for instance, comparing a Path object that represents a link with the Path object that points to the same file/folder as the link itself with method Files.isSameFile() should return true. The only methods that are an exception to this rule are deletion methods (delete the link and no the referred file), motion (move the link, not the file) and Files.walkFileTree(), which does not navigate into directories pointed by links;
Integration with the old API: in case you need to mix java.io code with NIO.2, it's possible to create a Path object from a File object – file.toPath() – and vice-versa – path.toFile();
Extensibility: NIO.2 can be extended to handle other types of file systems to which support is not yet given. As a proof of concept, JDK 7 brings among its examples a FileSystem implementation for ZIP files, which allows us to manipulate contents of compressed archives transparently, as if they were files directly in the file system. For example, if p1 is a Path object obtained from the ZIP file system and p2 a Path from the default file system, the operation Files.copy(p1, p2) will copy the file from the compressed archive, automatically decompressing it, to the default file system. Decompression is provided by the ZIP file system implementation.


colunista nao disponivel

What did you think of this post?
Services
[Close]
To have full access to this post (or download the associated files) you must have MrBool Credits.

  See the prices for this post in Mr.Bool Credits System below:

Individually – in this case the price for this post is US$ 0,00 (Buy it now)
in this case you will buy only this video by paying the full price with no discount.

Package of 10 credits - in this case the price for this post is US$ 0,00
This subscription is ideal if you want to download few videos. In this plan you will receive a discount of 50% in each video. Subscribe for this package!

Package of 50 credits – in this case the price for this post is US$ 0,00
This subscription is ideal if you want to download several videos. In this plan you will receive a discount of 83% in each video. Subscribe for this package!


> More info about MrBool Credits
[Close]
You must be logged to download.

Click here to login