New to Java? We'll help you get started with our revised beginner's tutorial, or our free online textbook.


Get the latest Java books
h t t p : / /w w w . j a v a c o f f e e b r e a k . c o m /

Java Coffee Break

Solution for
Programming Exercise 11.1


THIS PAGE DISCUSSES ONE POSSIBLE SOLUTION to the following exercise from this on-line Java textbook.

Exercise 11.1: The DirectoryList program, given as an example at the end of Section 10.2, will print a list of files in a directory specified by the user. But some of the files in that directory might themselves be directories. And the subdirectories can themselves contain directories. And so on. Write a modified version of DirectoryList that will list all the files in a directory and all its subdirectories, to any level of nesting. You will need a recursive subroutine to do the listing. The subroutine should have a parameter of type File. You will need the constructor from the File class that has the form

         public File( File dir, String fileName )
            // Constructs the File object representing a file
            // named fileName in the directory specified by dir.

Discussion

One possible recursive algorithm for printing all the files in a directory and its subdirectories is:

           Print the name of the directory
           for each file in the directory:
              if the file is a directory:
                 Print its contents recursively
              else
                 Print the name of the file.

If the directory is given as an object of type File, then this can be coded easily. We need some instance methods from the File class. (This subroutine is not quite what I ended up using in my solution.)

       static void listContents( File dir ) {
              // Assume that dir is a directory.  List
              // its contents, including the contents of
              // subdirectories at all levels.
           TextIO.putln("Directory \"" + dir.getName() + "\"");  
           String[] files;  // The names of the files in the directory.
           files = dir.list();
           for (int i = 0; i < files.length; i++) {
               File f;  // One of the files in the directory.
               f = new File(dir, files[i]);
               if ( f.isDirectory() ) {
                      // Call listContents() recursively to
                      // list the contents of the directory, f.
                   listContents(f);
               }
               else {
                     // For a regular file, just print the name, files[i].
                   TextIO.putln(files[i]);
               }
           }
       } // end listContents()

Every time this routine finds a directory, it lists not just the name of the directory but also, recursively, the names of everything that it contains. The only problem with this is that it doesn't indicate which items are in which directory. For example, if the output is

           Directory "games"
           blackbox
           Directory "CardGames"
           cribbage
           euchre
           tetris

there is no way to tell where the list of items in "CardGames" ends. Possibly, for example, "euchre" is in the "CardGames" directory. But possibly, "cribbage" is the only file in "CardGames" and "euchre" is actually part of the listing for "games". It would be nice to use indentation to show the nesting, like this:

           Directory "games"
             blackbox
             Directory "CardGames"
               cribbage
               euchre
             tetris

In this listing, you can tell that "cribbage" is in fact in "CardGames" while "tetris" is in "games". To implement this, we just have to recognize that the indentation can be different in each call to the listContents() method. Since it can be different, it should be a parameter. When we call listContents() recursively, we should increase the indentation. You can see how this is done in the actual solution, given below.


The Solution

   /* 
       This program lists the contents of a directory specified by
       the user.  The contents of subdirectories are also listed,
       up to any level of nesting.  Indentation is used to show 
       the level of nesting.
   
       The user is asked to type in a directory name.
       If the name entered by the user is not a directory, a
       message is printed and the program ends.
   */
         
   
   import java.io.*;
   
   public class RecursiveDirectoryList {
   
      public static void main(String[] args) {
      
         String directoryName;  // Directory name entered by the user.
         File directory;        // File object referring to the directory.
      
         TextIO.put("Enter a directory name: ");
         directoryName = TextIO.getln().trim();
         directory = new File(directoryName);
         
         if (directory.isDirectory() == false) {
                // Program needs a directory name.  Print an error message.
             if (directory.exists() == false)
                TextIO.putln("There is no such directory!");
             else
                TextIO.putln("That file is not a directory.");
         }
         else {
                // List the contents of directory, with no indentation
                // at the top level.
             listContents( directory, "" );
         }
      
      } // end main()
      
      
      static void listContents(File dir, String indent) {
              // A recursive subroutine that lists the contents of
              // the directory dir, including the contents of its
              // subdirectories to any level of nesting.  It is assumed
              // that dir is in fact a directory.  The indent parameter
              // is a string of blanks that is prepended to each item in
              // the listing.  It grows in length with each increase in
              // the level of directory nesting.
          String[] files;  // List of names of files in the directory.
          TextIO.putln(indent + "Directory \"" + dir.getName() + "\":");
          indent += "  ";  // Increase the indentation for listing the contents.
          files = dir.list();
          for (int i = 0; i < files.length; i++) {
                   // If the file is a  directory, list its contents
                   // recursively.  Otherwise, just print its name.
              File f = new File(dir, files[i]);
              if (f.isDirectory())
                 listContents(f, indent);
              else
                 TextIO.putln(indent + files[i]);
          }
      } // end listContents()
         
   
   } // end class RecursiveDirectoryList
   

[ Exercises | Chapter Index | Main Index ]