The use of recursive calls

The term "recursive" means in computer science a function call that calls itself, in a way such that you can traverse a tree.  A tree contains nodes and leaves.  You would process the leaves and call the function again for nodes recursively.

Consider traversing a directory structure.  File#list() does not list up all the subdirectories.  It is a matter of writing a function that calls itself, i.e., process the files and call the same function for directories.

This procedure can be generalized.  Instead of writing the recursive call, here I wrote a class called RecurseDir.  This is an abstract class that calls on the specified file directory recursively.

import java.io.File;

public abstract class RecurseDir {
    /**
     * Executed on each file.
     * 
     * @param fileName
     */
    public abstract void executeOnFile(String fileName);

    /**
     * Executed on each directory.
     * 
     * @param fileName
     */
    public abstract void executeOnDirectory(String fileName);

    /**
     * Main recursive loop that goes down each sub directory.
     * 
     * @param dirName
     */
    public void applyCommand(String dirName) {
        try {
            if(dirName==null){
                throw new Exception ("Directory name not set");
            }
            File dir = new File(dirName);
            String path = dir.getAbsolutePath();
            String list[] = dir.list();
            if (list != null) {
                for (String dirname : list) {
                    String pathname = path + File.separator + dirname;
                    File file = new File(pathname);
                    if (file.isDirectory()) {
                        executeOnDirectory(pathname);
                        applyCommand(pathname);
                    } else {
                        executeOnFile(pathname);
                    }
                }
            } else {
                executeOnFile(dirName);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}


You can use the above class directly in your project, or it is available in the central repository.

<dependency>
    <groupId>com.github.easai.utils</groupId>
    <artifactId>RecurseDir</artifactId>
    <version>0.0.1</version>
</dependency>

Create a RecurseDir derivative class.  Implement executeOnDirectory() and executeOnFile().  These are fuctions that processes directories and files, respectively.  Then call applyCommand().  The functions will be called upon the specified directory and its sub-directories recursively.

import java.io.File;

import org.apache.commons.cli.CommandLine;
import org.apache.commons.cli.CommandLineParser;
import org.apache.commons.cli.DefaultParser;
import org.apache.commons.cli.HelpFormatter;
import org.apache.commons.cli.Option;
import org.apache.commons.cli.Options;

import com.github.easai.utils.RecurseDir;

public class DirList extends RecurseDir {

    final static String OPTION_HELP = "help";
    final static String OPTION_DIR = "dir";

    DirList(String dir) {
        applyCommand(dir);
    }

    /*
     * Each directory name will be printed followed by a colon.
     *
     * @see easai.util.RecurseDir#executeOnDirectory(java.lang.String)
     */
    public void executeOnDirectory(String fileName) {
        System.out.println();
        System.out.println(fileName + ":");
    }

    /*
     * Each file name will be printed (one per line).
     *
     * @see easai.util.RecurseDir#executeOnFile(java.lang.String)
     */
    public void executeOnFile(String fileName) {
        try {
            File file = new File(fileName);
            System.out.println(file.getPath());
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * DirList is a utility that prints out all files under the specified
     * directory, including all the sub-directories.
     *
     * Usage: java -jar DirList.jar [directory]
     *
     * @param args
     */
    public static void main(String args[]) {
        Options opt = new Options();
        try {
            opt.addOption("?", OPTION_HELP, false, "print this message");           

             Option option = Option.builder("d")
                     .required(true)
                     .longOpt(OPTION_DIR)
                     .hasArgs()
                     .desc("print recursively the files in the specified directory")
                     .build();
            
             opt.addOption(option);
            
            CommandLineParser parser = new DefaultParser();
            CommandLine cmd = parser.parse(opt, args);
            if (cmd.hasOption(OPTION_HELP)) {
                throw new Exception();
            } else {
                String dir[] = cmd.getOptionValues(OPTION_DIR);
                if (dir != null) {
                    for (String d : dir) {
                        new DirList(d);
                    }
                }
            }
        } catch (Exception e) {
            HelpFormatter help = new HelpFormatter();
            help.printHelp("DirList", opt, true);
        }
    }
}

Comments

Popular posts from this blog

Logging your Maven project with Logback

TreeEditor: Customizing Drag and Drop

Spring Tool Suite