File Dialogs
File dialogs are the standard open and save dialogs provided by the host GUI. Users use them to pick a directory and a name under which to save a file or to choose a file to open. The appearance varies from platform to platform, but the intent is the same. Figure 18-1 shows a standard Save dialog on the Mac; Figure 18-2 shows a standard open dialog on Linux.
Figure 18-1. The Mac's standard Save dialog
Figure 18-2. Gnome Open dialog
FileDialog is a subclass of java.awt.Dialog that represents the native save and open dialog boxes:
public class FileDialog extends Dialog
A file dialog is almost completely implemented by a native peer. Your program doesn't add components to a file dialog or handle user interaction with event listeners. It just displays the dialog and retrieves the name and directory of the file the user chose after the dialog is dismissed.
To ask the user to select a file from a file dialog, perform these four steps:
- Construct a FileDialog object.
- Set the default directory or file for the dialog (optional).
- Make the dialog visible.
- Get the name and directory of the file the user chose.
File dialogs are modal. While the file dialog is shown, input to the parent frame is blocked, as with the parent frame of any modal dialog. The parent frame is normally the window from whose menu bar File/Open was selected. The parent frame is always set in the constructor:
public FileDialog(Frame parent)
Starting in Java 5, you can use another Dialog as the parent if you prefer:
public FileDialog(Dialog parent) // Java 5
Each FileDialog usually has a title. This is the prompt string for the file dialog, such as "Open File" or "Save Message As". This is also set in the constructor:
public FileDialog(Frame parent, String title) public FileDialog(Dialog parent, String title) // Java 5
Finally, each FileDialog is either in open mode or save mode. The default for the previous constructors is open mode. However, this can be specified with one of these two constructors:
public FileDialog(Frame parent, String title, int mode) public FileDialog(Dialog parent, String title, int mode) // Java 5
The mode argument is one of the two mnemonic constants FileDialog.LOAD or FileDialog.SAVE:
public static final int LOAD = 0; public static final int SAVE = 1;
A typical invocation of this constructor might look like this:
FileDialog fd = new FileDialog(framePointer, "Please choose the file to open:", FileDialog.LOAD);
In load mode, the user chooses an existing file. In save mode the user can either choose an existing file or create a new one.
Getter and setter methods allow the mode to be inspected and changed after the dialog is constructed:
public int getMode( ) public void setMode(int mode)
To specify that the file dialog should appear with a particular directory opened or a particular file in that directory selected, you can invoke the setDirectory( ) and setFile( ) methods:
public void setDirectory(String directory) public void setFile(String file)
For example:
fd.setDirectory("/etc"); fd.setFile("passwd");
You make the file dialog visible by invoking the file dialog's setVisible(true) method, just like any other window:
fd.setVisible(true);
As soon as the file dialog becomes visible, the calling thread stops and waits for the user to choose a file. The operating system takes over and handles user interaction until the user chooses a file or presses the Cancel button. At this point, the file dialog disappears from the screen, and normal program execution resumes.
Once the dialog has been dismissed, you can find out which file the user chose by using the file dialog's getdirectory( ) and getFile( ) methods:
public String getFile( ) public String getDirectory( )
For example:
FileDialog fd = new FileDialog( new Frame( ), "Please choose a file:", FileDialog.LOAD); fd.setVisible(true); File f = new File(fd.getDirectory(), fd.getFile( ));
If the user cancels the file dialog without selecting a file, getFile( ) and geTDirectory( ) return null. You should be ready to handle this, or you'll bump into a NullPointerException in short order.
Example 18-1 is a program that presents an open file dialog to the user and writes the contents of the file she selected on System.out.
Example 18-1. The FileTyper program
import java.io.*; import java.awt.*; public class FileTyper { public static void main(String[] args) throws IOException { InputStream in = null; try { File f = getFile( ); if (f == null) return; in = new FileInputStream(f); for (int c = in.read(); c != -1; c = in.read( )) { System.out.write(c); } } finally { if (in != null) in.close( ); } // Work around annoying AWT non-daemon thread bug. System.exit(0); } public static File getFile( ) { // dummy Frame, never shown Frame parent = new Frame( ); FileDialog fd = new FileDialog(parent, "Please choose a file:", FileDialog.LOAD); fd.setVisible(true); // Program stops here until user selects a file or cancels. String dir = fd.getDirectory( ); String file = fd.getFile( ); // Clean up our windows, they won't be needed again. parent.dispose( ); fd.dispose( ); if (dir == null || file == null) { // user cancelled the dialog return null; } return new File(dir, file); } } |
File dialogs only allow the user to select ordinary files, never directories. To ask users to pick a directory, you have to ask them to choose a file in that directory and then call getdirectory( ). Better yet, you can use a JFileChooser (discussed in the next section) that does allow the user to choose a directory.
A filename filter can be attached to a file dialog via the dialog's setFilenameFilter( ) method:
public void setFilenameFilter(FilenameFilter filter)
Once a file dialog's filename filter is set, it should only display files that pass through the filter. However, filename filters in file dialogs are only reliable on Unix (including Linux and Mac OS X). Windows is almost congenitally unable to support it because Windows' native file chooser dialog can only filter by file extension.
Example 18-2 demonstrates a simple filename filter that accepts files ending in .text, .txt, .java, .jav, .html, and .htm; all others are rejected.
Example 18-2. TextFilter
import java.io.*; public class TextChooser implements FilenameFilter { public boolean accept(File dir, String name) { if (name.endsWith(".java")) return true; else if (name.endsWith(".jav")) return true; else if (name.endsWith(".html")) return true; else if (name.endsWith(".htm")) return true; else if (name.endsWith(".txt")) return true; else if (name.endsWith(".text")) return true; return false; } } |
This program demonstrates one problem of relying on file extensions to determine file type. Many other file extensions indicate text files, for example, .c, .cc, .pl, .f, and many more. Furthermore, many text files, especially those on Macintoshes, have no extension at all. This program completely ignores all those files.
You do not necessarily have to write a new subclass for each different file filter. Example 18-3 demonstrates a class that can be configured with different lists of filename extensions. Every file with an extension in the list passes the filter. Others don't.
Example 18-3. ExtensionFilenameFilter
package com.elharo.io; import java.awt.*; import java.util.*; import java.io.*; public class ExtensionFilenameFilter implements FilenameFilter { ArrayList extensions = new ArrayList( ); public ExtensionFilenameFilter(String extension) { if (extension.indexOf('.') != -1) { extension = extension.substring(extension.lastIndexOf('.')+1); } extensions.add(extension); } public void addExtension(String extension) { if (extension.indexOf('.') != -1) { extension = extension.substring(extension.lastIndexOf('.')+1); } extensions.add(extension); } public boolean accept(File directory, String filename) { String extension = filename.substring(filename.lastIndexOf('.')+1); if (extensions.contains(extension)) { return true; } return false; } } |
This class is designed to filter files by extension. You configure which extensions pass the filter when you create the object or by calling addExtension( ). This avoids excessive proliferation of classes.