Java NIO.2 Recursive Directory Listing Example

In this tutorial, we will teach you how to list all the directories inside a folder recursively in Java, using NIO.2. Specifically, we will look into FileVisitor interface (java.nio.file.FileVisitor) and implement the methods available in this interface, to traverse a folder. We will focus on listing the following items during our traversal in this example:

  • List Sub directory Name
  • List Absolute path of the directory
  • List Parent directory name
  • List relative path specific to a fixed path
  • Convert the sub-directory name to URI.

There are much more, we will look at them in our advanced examples later. The sample directory structure for this example is provided below:

Recursive directory Listing using NIO.2 - Sample folder structure
Recursive directory Listing using NIO.2 - Sample folder structure
The “test” folder is located under c: drive. 

FileVisitor Interface – Access Files and Directories


java.nio.file.SimpleFileVisitor interface implements FileVisitor,  and offers the key methods postVisitDirectory, preVisitDirectory, visitFile and visitFileFailed. In order to recursively list all directories, you can extend SimpleFileVisitor class, and override only those methods that you want, depending on your requirements. A brief overview on the methods we require for this tutorial / that we need to override is presented below:


postVisitDirectory: This method is invoked after all the sub-directories  / directory is visited. (for now, this much of explanation would be sufficient for this ). We will make use of this method, to traverse through all the sub-directories.

visitFileFailed: In the context of this post, this method will be invoked if the directory cannot be opened / traversed due to some reason. In this case, we get an exception back, which can be printed on the screen. You can take a decision to either abort the program execution, or continue accessing other directories.

Both these methods return an object of type, java.nio.file.FileVisitResult, through which you can either CONTINUE or TERMINATE the execution. Our approach would be to implement postVisitDirectory method to get list of directories, and visitFileFailed method to handle exceptions in this process.


walkFileTree – traverse directory structure:


ok, we got basic methods to traverse directories, but how do we initiate the traversal? java.nio.file.Files class has a method walkFileTree,(there are two versions of this method, we will use the simple one for this tutorial) which accepts a Path from where you have to start searching, and accepts a FileVisitor class, which it has to obey in the traversal process. This is the key linker for our program. It connects a path in our system to the methods we wrote earlier, so that all the directories are visited. The traversal is always done by depth first search method.  This method continues, until all files are traversed or a TERMINATE is encountered. 

The Java Program that prints all sub directories inside a folder recursively using NIO.2 should start by defining the generic FileVisitor interface method behaviour. It should then accept a Path where it can execute the generic methods defined, and pass this path to walkFileTree method, which will then call these methods for every directory encountered. Diagrammatically, it is shown below:

Approach in NIO.2 to list directory contents - Java Pseudo logic
Approach in NIO.2 to list directory contents - Java Pseudo logic


postVisitDirectory Implementation – Print Directory properties


In this method, we list all the output we want for every directory, using the methods available in Path class. The methods we use for our listing is shown below:

  • getFileName – to print the directory name.
  • toAbsolutePath – convert directory name to absolute path
  • getParent – to print the parent directory name
  • relativize – to print the path relative to a specified path
  • toUri – to convert the directory path to URI

The Java code snippet is shown below:
    @Override
    public FileVisitResult postVisitDirectory(Path dir, IOException exc)
    {
        System.out.println("");
        // Print Name of the directory     
        System.out.println("Directory Name: " + dir.getFileName());
        // Print absolute path for the directory
        System.out.println("Absolute Path: " + dir.toAbsolutePath());
        // Print parent directory name
        System.out.println("Parent Directory: " + dir.getParent().getFileName());
        // continue to the next directory
        // Get Relative path to C:
        Path relative_path_to = Paths.get("C:/");
        System.out.println("Relative Path: " + dir.relativize(relative_path_to));
        // URI of the directory
        System.out.println("URI: " + dir.toUri());
        return FileVisitResult.CONTINUE;
    }

Note that, we override this method as our class will extend SimpleFileVisitor class.


visitFileFailed Implementation – Handle Exception while Traversing:


We just print the exception and do nothing here. This is a tutorial for beginners, so we just give a CONTINUE when we encounter this exception. 

    @Override
    public FileVisitResult visitFileFailed(Path file, IOException traversalException)
    {
        // we throw an exception if the directory cannot be accessed for any reason    
        System.out.println(traversalException);
        // and continue traversing other directories
        return FileVisitResult.CONTINUE;
    }


Complete Java Program – List all directories – NIO.2


The complete Java program to print all the directories under a main folder in Java using NIO.2 is provided below:

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

class ListDirectories extends SimpleFileVisitor<Path>
{
    @Override
    public FileVisitResult postVisitDirectory(Path dir, IOException exc)
    {
        System.out.println("");
        // Print Name of the directory     
        System.out.println("Directory Name: " + dir.getFileName());
        // Print absolute path for the directory
        System.out.println("Absolute Path: " + dir.toAbsolutePath());
        // Print parent directory name
        System.out.println("Parent Directory: " + dir.getParent().getFileName());
        // continue to the next directory
        // Get Relative path to C:
        Path relative_path_to = Paths.get("C:/");
        System.out.println("Relative Path: " + dir.relativize(relative_path_to));
        // URI of the directory
        System.out.println("URI: " + dir.toUri());
        return FileVisitResult.CONTINUE;
    }
    @Override
    public FileVisitResult visitFileFailed(Path file, IOException traversalException)
    {
        // we throw an exception if the directory cannot be accessed for any reason    
        System.out.println(traversalException);
        // and continue traversing other directories
        return FileVisitResult.CONTINUE;
    }
    public static void main(String args[])  
    {
        Path search_directory_path = Paths.get("C:/test");
        //define the starting file tree
        ListDirectories traverser = new ListDirectories();
        //instantiate the walk
        try
        {
            Files.walkFileTree(search_directory_path, traverser);
            //start the walk
        }
        catch(IOException e)
        {
            System.err.println(e);
        }
    }
}

For the input we specified above, the output of the program is shown below:

java ListDirectories

Directory Name: f2
Absolute Path: C:\test\f1\f2
Parent Directory: f1
Relative Path: ..\..\..
URI: file:///C:/test/f1/f2/

Directory Name: f3
Absolute Path: C:\test\f1\f3
Parent Directory: f1
Relative Path: ..\..\..
URI: file:///C:/test/f1/f3/

Directory Name: f1
Absolute Path: C:\test\f1
Parent Directory: test
Relative Path: ..\..
URI: file:///C:/test/f1/

Directory Name: f4
Absolute Path: C:\test\f4
Parent Directory: test
Relative Path: ..\..
URI: file:///C:/test/f4/

Directory Name: test
Absolute Path: C:\test
Parent Directory: null
Relative Path: ..
URI: file:///C:/test/


which works exactly the way we wanted. We are now ready to see some advanced examples in NIO.2 to perform file traversals. We will be publishing them as we move on with the tutorial. Meanwhile, if you have any suggestions to improve the code, please post it in the comments section.

No comments:

Post a Comment