[ Team LiB ] Previous Section Next Section

3.5 Listing Directory and File Information

Just as the FileViewer class of Example 3-3 displays the contents of a file in a TextArea component, the FileLister class, shown in Example 3-4, displays the contents of a directory in a java.awt.List component. When you select a file or directory name from the list, the program displays information (size, modification date, etc.) about the file or directory in a TextField component. When you double-click on a directory, the contents of that directory are displayed. When you double-click on a file, it displays the contents of the file in a FileViewer object. Figure 3-2 shows a FileLister window. Again, if you are not already familiar with GUI programming in Java, don't expect to understand all of the code until you've read Chapter 11; instead, just pay attention to the various uses of the File object that are demonstrated in this example.

Figure 3-2. A FileLister window
figs/Jex3_0302.gif

The GUI mechanics of making the FileLister work form a large part of this example. The listDirectory( ) method lists the contents of a directory, using an optionally specified FilenameFilter object passed to the FileLister( ) constructor. This object defines an accept( ) method that is called for every entry in a directory to determine whether it should be listed.

The itemStateChanged( ) method is invoked when an item in the list is selected. It obtains information about the file or directory and displays it. The actionPerformed( ) method is another event listener method. This one is invoked when the user clicks either of the Button objects or double-clicks on an item in the list. If the user double-clicks on a directory, the program lists the contents of that directory. If the user double-clicks on a file, however, it creates and displays a FileViewer window to list the contents of the file.

Like the FileViewer class, the FileLister can be used by other classes, or it can be invoked as a standalone program. If you invoke it standalone, it lists the contents of the current directory. You can also invoke it with an optional directory name to see the contents of that directory. Using the optional -e flag followed by a file extension causes the program to filter the list of files and displays only the ones that have the specified extension. Note how the main( ) method parses the command-line arguments and uses an anonymous class to implement the FilenameFilter interface.

Example 3-4. FileLister.java
package je3.io;
import java.awt.*;
import java.awt.event.*;
import java.io.*;
import java.text.DateFormat;
import java.util.Date;

/** 
 * This class creates and displays a window containing a list of
 * files and sub-directories in a specified directory.  Clicking on an
 * entry in the list displays more information about it. Double-clicking 
 * on an entry displays it, if a file, or lists it if a directory.
 * An optionally-specified FilenameFilter filters the displayed list.
 **/
public class FileLister extends Frame implements ActionListener, ItemListener {
    private List list;                  // To display the directory contents in
    private TextField details;          // To display detail info in
    private Panel buttons;              // Holds the buttons
    private Button up, close;           // The Up and Close buttons
    private File currentDir;            // The directory currently listed
    private FilenameFilter filter;      // An optional filter for the directory
    private String[  ] files;             // The directory contents
    private DateFormat dateFormatter =  // To display dates and time correctly
          DateFormat.getDateTimeInstance(DateFormat.SHORT, DateFormat.SHORT);
    
    /** 
     * Constructor: create the GUI, and list the initial directory. 
     **/
    public FileLister(String directory, FilenameFilter filter) { 
        super("File Lister");              // Create the window
        this.filter = filter;              // Save the filter, if any
        
        // Destroy the window when the user requests it
        addWindowListener(new WindowAdapter( ) {
                public void windowClosing(WindowEvent e) { dispose( ); }
            });

        list = new List(12, false);        // Set up the list
        list.setFont(new Font("MonoSpaced", Font.PLAIN, 14));
        list.addActionListener(this);
        list.addItemListener(this);
        
        details = new TextField( );         // Set up the details area
        details.setFont(new Font("MonoSpaced", Font.PLAIN, 12));
        details.setEditable(false);

        buttons = new Panel( );             // Set up the button box
        buttons.setLayout(new FlowLayout(FlowLayout.RIGHT, 15, 5));
        buttons.setFont(new Font("SansSerif", Font.BOLD, 14));

        up = new Button("Up a Directory"); // Set up the two buttons
        close = new Button("Close");
        up.addActionListener(this);
        close.addActionListener(this);

        buttons.add(up);                   // Add buttons to button box
        buttons.add(close);
        
        this.add(list, "Center");          // Add stuff to the window
        this.add(details, "North");
        this.add(buttons, "South");
        this.setSize(500, 350);
        
        listDirectory(directory);          // And now list initial directory.
    }
    
    /**
     * This method uses the list( ) method to get all entries in a directory
     * and then displays them in the List component. 
     **/
    public void listDirectory(String directory) {
        // Convert the string to a File object, and check that the dir exists
        File dir = new File(directory);
        if (!dir.isDirectory( )) 
           throw new IllegalArgumentException("FileLister: no such directory");

        // Get the (filtered) directory entries
        files = dir.list(filter);        

        // Sort the list of filenames.
        java.util.Arrays.sort(files);
        
        // Remove any old entries in the list, and add the new ones
        list.removeAll( );
        list.add("[Up to Parent Directory]");  // A special case entry
        for(int i = 0; i < files.length; i++) list.add(files[i]);
        
        // Display directory name in window titlebar and in the details box
        this.setTitle(directory);
        details.setText(directory);
        
        // Remember this directory for later.
        currentDir = dir;
    }
    
    /**
     * This ItemListener method uses various File methods to obtain information
     * about a file or directory. Then it displays that info.
     **/
    public void itemStateChanged(ItemEvent e) {
        int i = list.getSelectedIndex( ) - 1;  // minus 1 for Up To Parent entry
        if (i < 0) return;
        String filename = files[i];               // Get the selected entry 
        File f = new File(currentDir, filename);  // Convert to a File
        if (!f.exists( ))                          // Confirm that it exists
            throw new IllegalArgumentException("FileLister: " +
                                               "no such file or directory");

        // Get the details about the file or directory, concatenate to a string
        String info = filename;
        if (f.isDirectory( )) info += File.separator;
        info += " " + f.length( ) + " bytes ";
        info += dateFormatter.format(new java.util.Date(f.lastModified( )));
        if (f.canRead( )) info += " Read";
        if (f.canWrite( )) info += " Write";
        
        // And display the details string
        details.setText(info);
    }
    
    /**
     * This ActionListener method is invoked when the user double-clicks on an 
     * entry or clicks on one of the buttons.  If they double-click on a file,
     * create a FileViewer to display that file.  If they double-click on a
     * directory, call the listDirectory( ) method to display that directory
     **/
    public void actionPerformed(ActionEvent e) {
        if (e.getSource( ) == close) this.dispose( );
        else if (e.getSource( ) == up) { up( ); }
        else if (e.getSource( ) == list) {  // Double-click on an item
            int i = list.getSelectedIndex( ); // Check which item
            if (i == 0) up( );                // Handle first Up To Parent item
            else {                           // Otherwise, get filename
                String name = files[i-1]; 
                File f = new File(currentDir, name);    // Convert to a File
                String fullname = f.getAbsolutePath( );
                if (f.isDirectory( )) listDirectory(fullname);  // List dir
                else new FileViewer(fullname).show( );          // display file
            }
        }
    }
    
    /** A convenience method to display the contents of the parent directory */
    protected void up( ) {
        String parent = currentDir.getParent( );
        if (parent == null) return;
        listDirectory(parent);
    }
    
    /** A convenience method used by main( ) */
    public static void usage( ) {
        System.out.println("Usage: java FileLister [directory_name] " + 
                           "[-e file_extension]");
        System.exit(0);
    }
    
    /**
     * A main( ) method so FileLister can be run standalone.
     * Parse command-line arguments and create the FileLister object.
     * If an extension is specified, create a FilenameFilter for it.
     * If no directory is specified, use the current directory.
     **/
    public static void main(String args[  ]) throws IOException {
        FileLister f;
        FilenameFilter filter = null;  // The filter, if any
        String directory = null;       // The specified dir, or the current dir
        
        // Loop through args array, parsing arguments
        for(int i = 0; i < args.length; i++) {
            if (args[i].equals("-e")) {
                if (++i >= args.length) usage( );
                final String suffix = args[i];  // final for anon. class below

                // This class is a simple FilenameFilter.  It defines the
                // accept( ) method required to determine whether a specified
                // file should be listed.  A file will be listed if its name
                // ends with the specified extension, or if it is a directory.
                filter = new FilenameFilter( ) {
                        public boolean accept(File dir, String name) {
                            if (name.endsWith(suffix)) return true;
                            else return (new File(dir, name)).isDirectory( );
                        }
                    };
            }
            else {
                if (directory != null) usage( );  // If already specified, fail.
                else directory = args[i];
            }
        }
        
        // if no directory specified, use the current directory
        if (directory == null) directory = System.getProperty("user.dir");
        // Create the FileLister object, with directory and filter specified.
        f = new FileLister(directory, filter);
        // Arrange for the application to exit when the window is closed
        f.addWindowListener(new WindowAdapter( ) {
            public void windowClosed(WindowEvent e) { System.exit(0); }
        });
        // Finally, pop the window up.
        f.show( );
    }
}
    [ Team LiB ] Previous Section Next Section