Home | | Web Programming | Use NIO for Path and File System Operations

Chapter: Java The Complete Reference : The Java Library : Input/Output: Exploring java.io

Use NIO for Path and File System Operations

At the beginning of Chapter 20, the File class in the java.io package was examined. As explained there, the File class deals with the file system and with the various attributes associated with a file, such as whether a file is read-only, hidden, and so on.

Use NIO for Path and File System Operations

 

At the beginning of Chapter 20, the File class in the java.io package was examined. As explained there, the File class deals with the file system and with the various attributes associated with a file, such as whether a file is read-only, hidden, and so on. It was also used to obtain information about a file’s path. Although the File class is still perfectly acceptable, the interfaces and classes defined by NIO.2 offer a better way to perform these functions. The benefits include support for symbolic links, better support for directory tree traversal, and improved handling of metadata, among others. The following sections show samples of two common file system operations: obtaining information about a path and file and getting the contents of a directory.

Obtain Information About a Path and a File

 

Information about a path can be obtained by using methods defined by Path. Some attributes associated with the file described by a Path (such as whether or not the file is hidden) are obtained by using methods defined by Files. The Path methods used here are getName( ), getParent( ), and toAbsolutePath( ). Those provided by Files are isExecutable( ), isHidden( ), isReadable( ), isWritable( ), and exists( ). These are summarized in Tables 21-3 and 21-4, shown earlier.

Other file attributes are obtained by requesting a list of attributes by calling Files.readAttributes( ). In the program, this method is called to obtain the BasicFileAttributes associated with a file, but the general approach applies to other types of attributes.

 

The following program demonstrates several of the Path and Files methods, along with several methods provided by BasicFileAttributes. This program assumes that a file called test.txt exists in a directory called examples, which must be a subdirectory of the current directory.

 

    //Obtain information about a path and a file.

 

    //Requires JDK 7 or later.

 

import java.io.*; import java.nio.file.*;

import java.nio.file.attribute.*;

 

class PathDemo {

 

public static void main(String args[]) {

 

Path filepath = Paths.get("examples\\test.txt");

System.out.println("File Name: " + filepath.getName(1));

System.out.println("Path: " + filepath);

System.out.println("Absolute Path: " + filepath.toAbsolutePath());

System.out.println("Parent: " + filepath.getParent());

f(Files.exists(filepath)) System.out.println("File exists");

else

 

System.out.println("File does not exist");

 

try { if(Files.isHidden(filepath))

System.out.println("File is hidden"); else

System.out.println("File is not hidden"); } catch(IOException e) {

System.out.println("I/O Error: " + e);

 

}

 

Files.isWritable(filepath);

 

System.out.println("File is writable");

 

 

Files.isReadable(filepath); System.out.println("File is readable");

 

try {

 

BasicFileAttributes attribs =

 

Files.readAttributes(filepath, BasicFileAttributes.class);

 

if(attribs.isDirectory()) System.out.println("The file is a directory");

else

 

System.out.println("The file is not a directory");

 

if(attribs.isRegularFile()) System.out.println("The file is a normal file");

else

 

System.out.println("The file is not a normal file");

 

if(attribs.isSymbolicLink())

 

System.out.println("The file is a symbolic link"); else

System.out.println("The file is not a symbolic link");

 

System.out.println("File last modified: " + attribs.lastModifiedTime());

System.out.println("File size: " + attribs.size() + " Bytes");

} catch(IOException e) {

 

System.out.println("Error reading attributes: " + e);

 

}

 

}

If you execute this program from a directory called MyDir, which has a subdirectory called examples, and the examples directory contains the test.txt file, then you will see output similar to that shown here. (Of course, the information you see will differ.)

 

File Name: test.txt

 

Path: examples\test.txt

 

Absolute Path: C:\MyDir\examples\test.txt

 

Parent: examples

 

File exists

 

File is not hidden

 

File is writable

 

File is readable

 

The file is not a directory

 

The file is a normal file

 

The file is not a symbolic link

 

File last modified: 2014-01-01T18:20:46.380445Z

 

File size: 18 Bytes

 

If you are using a computer that supports the FAT file system (i.e., the DOS file system), then you might want to try using the methods defined by DosFileAttributes. If you are using a POSIX-compatible system, then try using PosixFileAttributes.

 

List the Contents of a Directory

 

If a path describes a directory, then you can read the contents of that directory by using static methods defined by Files. To do this, you first obtain a directory stream by calling newDirectoryStream( ), passing in a Path that describes the directory. One form of newDirectoryStream( ) is shown here:

 

static DirectoryStream<Path> newDirectoryStream(Path dirPath) throws IOException

 

Here, dirPath encapsulates the path to the directory. The method returns a DirectoryStream<Path> object that can be used to obtain the contents of the directory. It will throw an IOException if an I/O error occurs and a NotDirectoryException (which is a subclass of IOException) if the specified path is not a directory. A SecurityException is also possible if access to the directory is not permitted.

 

DirectoryStream<Path> implements AutoCloseable, so it can be managed by a try-with-resources statement. It also implements Iterable<Path>. This means that you can obtain the contents of the directory by iterating over the DirectoryStream object. When iterating, each directory entry is represented by a Path instance. An easy way to iterate over a DirectoryStream is to use a for-each style for loop. It is important to understand, however, that the iterator implemented by DirectoryStream<Path> can be obtained only once for each instance. Thus, the iterator( ) method can be called only once, and a for-each loop can be executed only once.

 

The following program displays the contents of a directory called MyDir:

 

// Display a directory. Requires JDK 7 or later.

 

import java.io.*; import java.nio.file.*;

import java.nio.file.attribute.*;

class DirList {

 

public static void main(String args[]) {

String dirname = "\\MyDir";

 

// Obtain and manage a directory stream within a try block.

try ( DirectoryStream<Path> dirstrm =

 

Files.newDirectoryStream(Paths.get(dirname)) )

 

{

 

System.out.println("Directory of " + dirname);

 

    //Because DirectoryStream implements Iterable, we

 

    //can use a "foreach" loop to display the directory.

 

    for(Path entry : dirstrm) {

 

BasicFileAttributes attribs =

 

Files.readAttributes(entry, BasicFileAttributes.class);

 

if(attribs.isDirectory()) System.out.print("<DIR> ");

 

else

 

System.out.print("       ");

 

System.out.println(entry.getName(1));

 

}

 

} catch(InvalidPathException e) { System.out.println("Path Error " + e);

 

} catch(NotDirectoryException e) { System.out.println(dirname + " is not a directory.");

 

} catch (IOException e) { System.out.println("I/O Error: " + e);

}

 

}

 

}

 

Here is sample output from the program:

 

Directory of \MyDir DirList.class DirList.java

 

<DIR>       examples Test.txt

 

You can filter the contents of a directory in two ways. The easiest is to use this version of newDirectoryStream( ):

 

static DirectoryStream<Path> newDirectoryStream(Path dirPath, String wildcard) throws IOException

 

In this version, only files that match the wildcard filename specified by wildcard will be obtained. For wildcard, you can specify either a complete filename or a glob. A glob is a string that defines a general pattern that will match one or more files using the familiar * and ? wildcard characters.

These match zero or more of any character and any one character, respectively. The following are also recognized within a glob.


You can specify a * or ? character, using \* and \?. To specify a \, use \\. You can experiment with a glob by substituting this call to newDirectoryStream( ) into the previous program:

 

Files.newDirectoryStream(Paths.get(dirname), "{Path,Dir}*.{java,class}")

 

This obtains a directory stream that contains only those files whose names begin with either "Path" or "Dir" and use either the "java" or "class" extension. Thus, it would match names like DirList.java and PathDemo.java, but not MyPathDemo.java, for example.

 

Another way to filter a directory is to use this version of newDirectoryStream( ):

 

static DirectoryStream<Path> newDirectoryStream(Path dirPath, DirectoryStream.Filter<? super Path> filefilter)

throws IOException

 

Here, DirectoryStream.Filter is an interface that specifies the following method: boolean accept(T entry) throws IOException

 

In this case, T will be Path. If you want to include entry in the list, return true. Otherwise, return false. This form of newDirectoryStream( ) offers the advantage of being able to filter a directory based on something other than a filename. For example, you can filter based on size, creation date, modification date, or attribute, to name a few.

 

The following program demonstrates the process. It will list only those files that are writable.

 

// Display a directory of only those files that are writable.

 

import java.io.*; import java.nio.file.*;

import java.nio.file.attribute.*;

 

class DirList {

 

public static void main(String args[]) { String dirname = "\\MyDir";

 

// Create a filter that returns true only for writable files.

DirectoryStream.Filter<Path> how = new DirectoryStream.Filter<Path>() {

 

public boolean accept(Path filename) throws IOException {

if(Files.isWritable(filename)) return true;

 

return false;

 

}

 

};

// Obtain and manage a directory stream of writable files.

try (DirectoryStream<Path> dirstrm =

Files.newDirectoryStream(Paths.get(dirname), how) )

 

{

 

System.out.println("Directory of " + dirname);

 

for(Path entry : dirstrm) { BasicFileAttributes attribs =

 

Files.readAttributes(entry, BasicFileAttributes.class);

 

if(attribs.isDirectory()) System.out.print("<DIR> ");

 

else

 

System.out.print("       ");

 

System.out.println(entry.getName(1));

 

}

 

} catch(InvalidPathException e) { System.out.println("Path Error " + e);

 

} catch(NotDirectoryException e) { System.out.println(dirname + " is not a directory.");

 

} catch (IOException e) { System.out.println("I/O Error: " + e);

}

 

}

 

}

 

Use walkFileTree( ) to List a Directory Tree

 

The preceding examples have obtained the contents of only a single directory. However, sometimes you will want to obtain a list of the files in a directory tree. In the past, this was quite a chore, but NIO.2 makes it easy because now you can use the walkFileTree( ) method defined by Files to process a directory tree. It has two forms. The one used in this chapter is shown here:

 

static Path walkFileTree(Path root, FileVisitor<? extends Path> fv) throws IOException

 

The path to the starting point of the directory walk is passed in root. An instance of FileVisitor is passed in fv. The implementation of FileVisitor determines how the directory tree is traversed, and it gives you access to the directory information. If an I/O error occurs, an IOException is thrown. A SecurityException is also possible.

 

FileVisitor is an interface that defines how files are visited when a directory tree is traversed. It is a generic interface that is declared like this:

 

interface FileVisitor<T>

For use in walkFileTree( ), T will be Path (or any type derived from Path). FileVisitor defines the following methods.


Notice that each method returns a FileVisitResult. This enumeration defines the following  values: 

 

In general, to continue traversing the directory and subdirectories, a method should return

 

CONTINUE. For preVisitDirectory( ), return SKIP_SIBLINGS to bypass the directory and its siblings and prevent postVisitDirectory( ) from being called. To bypass just the directory and subdirectories, return SKIP_SUBTREE. To stop the directory traversal, return

TERMINATE.

 

Although it is certainly possible to create your own visitor class that implements these methods defined by FileVisitor, you won’t normally do so because a simple implementation is provided by SimpleFileVisitor. You can just override the default implementation of the method or methods in which you are interested. Here is a short example that illustrates the process. It displays all files in the directory tree that has \MyDir as its root. Notice how short this program is.

 

    //A simple example that uses walkFileTree( ) to display a directory tree.

 

    //Requires JDK 7 or later.

 

import java.io.*; import java.nio.file.*;

import java.nio.file.attribute.*;

 

 

    //Create a custom version of SimpleFileVisitor that overrides the visitFile( ) method.

 

class MyFileVisitor extends SimpleFileVisitor<Path> {

 

public FileVisitResult visitFile(Path path, BasicFileAttributes attribs)

 

throws IOException

 

{

 

System.out.println(path);

 

return FileVisitResult.CONTINUE;

 

}

 

}

 

class DirTreeList {

 

public static void main(String args[]) { String dirname = "\\MyDir";

 

System.out.println("Directory tree starting with " + dirname + ":\n");

 

try {

 

Files.walkFileTree(Paths.get(dirname), new MyFileVisitor());

 

} catch (IOException exc) { System.out.println("I/O Error");

}

 

}

 

}

 

Here is sample output produced by the program when used on the same MyDir directory shown earlier. In this example, the subdirectory called examples contains one file called MyProgram.java.

 

Directory tree starting with \MyDir:

 

\MyDir\DirList.class

 

\MyDir\DirList.java

 

\MyDir\examples\MyProgram.java

 

\MyDir\Test.txt

 

In the program, the class MyFileVisitor extends SimpleFileVisitor, overriding only the visitFile( ) method. In this example, visitFile( ) simply displays the files, but more sophisticated functionality is easy to achieve. For example, you could filter the files or perform actions on the files, such as copying them to a backup device. For the sake of clarity, a named class was used to override visitFile( ), but you could also use an anonymous inner class.

One last point: It is possible to watch a directory for changes by using java.nio.file.WatchService.

 


Study Material, Lecturing Notes, Assignment, Reference, Wiki description explanation, brief detail
Java The Complete Reference : The Java Library : Input/Output: Exploring java.io : Use NIO for Path and File System Operations |


Privacy Policy, Terms and Conditions, DMCA Policy and Compliant

Copyright © 2018-2024 BrainKart.com; All Rights Reserved. Developed by Therithal info, Chennai.