An introduction to I/O and the File and FileDialog classes in JAVA
Posted On August 3, 2007 by Rose Mary filed under Java
Nearly all programs require the ability to transfer data in and out of memory. For example, data may be stored on disk or sent over a network.
Java provides many classes that make "I/O" (input and output) relatively easy and platform independent. In this article, you will learn how to act upon the file structure of a platform from inside a Java application. Note that Java applets are NOT permitted to access a platform's file structure for security reasons.
The File class
· Is part of the java.io package. You will need an import statement to access the class with its abbreviated name.
· Is an extension of the Object class
Object
File
· Encapsulates platform-independent information about a file or a directory.
While all platforms use pathname strings to name files and directories, they do not agree on the format of these strings. For example, the Windows pathname string is not the same as the Unix pathname string.
Regardless of platform, however, all pathnames have two components:
1. An optional system-dependent prefix string (such as the disk-drive specifier followed by "/" for the Unix root directory or "" for the Windows root directory)
2. A sequence of zero or more string names where each name, except for the last, denotes a directory. The the last name may denote either a directory or a file. A system-dependent separator ("/" for Unix or "" for Windows) is used between each name.
For example, the following represents a valid Windows pathname:
C:My DocumentsNew CoursesArticle55.htm
Regardless of the platform, the File class presents a system-independent view of pathnames.
· Has a number of static fields. These two are the most useful:
| Field | Usage |
| separator | The String representation of the filename separator used on the current platform. |
| separatorChar | The char representation of the filename separator used on the current platform. |
For example, the following program can determine if it is running under Windows:
import java.io.*;
public class App {
public static void main(String[] args) {
if (File.separator.equals(""))
System.out.println("Windows");
else
System.out.println("Not Windows");
}
}
Note that the double backslash is required to because a single backslash denotes an escape sequence.
· Has several constructors. The most frequently used constructs a File object from a pathname string as shown by the following statement:
File f = new File("C:My DocumentsMiscResume.doc");
NOTE: Constructing a File object does NOT create a disk file. It only constructs a platform-independent object for referencing the file.
· Has a number of methods, some of which WILL create, rename, and delete a disk file or a directory. They should obviously be used with caution. The most frequently used methods are:
| Method | Usage |
| createNewFile() | Atomically creates a new, empty file named by this pathname if and only if a file with this name does not yet exist |
| delete() | Deletes the file or directory denoted by this pathname |
| exists() | Tests whether the file denoted by this pathname exists |
| getName() | Returns the name of the file or directory denoted by this pathname |
| getParent() | Returns the pathname of this pathname's parent, or null if this pathname does not name a parent directory |
| getPath() | Returns the pathname string of this pathname |
| isDirectory() | Tests whether this pathname is a directory |
| isFile() | Tests whether this pathname is a file |
| lastModified() | Returns the time that the file denoted by this pathname was last modified |
| length() | Returns the length of the file denoted by this pathname |
| list() | Returns an array of strings naming the files and directories in the directory denoted by this pathname |
| mkdir() | Creates the directory named by this pathname |
| renameTo() | Renames the file denoted by this pathname |
Consult the Java API documentation for more details.
The FileDialog class
· Is part of the java.awt package. You will need an import statement to access the class with its abbreviated name.
· Has many ancestor classes as indicated by the following diagram:
Object
Component
Container
Window
Dialog
FileDialog
· Can be instantiated to display a modal dialog window from which the user can select a file. Because it is a modal dialog, once an application makes a FileDialog object visible, it cannot continue until the user has chosen a file.
· Has two static fields that indicate whether the file will be used for input or output. They are
| Field | Usage |
| LOAD | Indicates that the purpose of the file dialog window is to locate a file from which to read |
| SAVE | Indicates that the purpose of the file dialog window is to locate a file to which to write |
· Has several constructors. The most frequently used is demonstrated by
FileDialog fd = new FileDialog(this, "Choose file", FileDialog.LOAD);
fd.setVisible(true);
which constructs and displays a file dialog window for the current (this) object. The title of the file dialog window will be "Choose file", and the chosen file will be used for input.
· Has a number of methods. The most frequently used are as follows:
| Method | Usage |
| getDirectory() | Returns a String representing the directory of the selected file |
| getFile() | Returns a String representing the filename of the selected file |
| setDirectory() | Sets the directory of this file dialog window to be the specified directory |
| setFile() | Sets the selected file for this file dialog window to be the specified file |
Consult the Java API documentation for more details.
Sample program
The following menu-driven, Windows program uses the File and FileDialog classes to display a variety of information about a file selected by the user:
| import java.awt.*; import java.awt.event.*; import java.util.*; import java.io.*; public class App extends Frame implements ActionListener { // Object references. MenuBar mainBar; Menu fileMenu; MenuItem find; MenuItem exit; TextArea fileInfo; // Processing starts here. public static void main(String[] args) { App myWindow = new App("File Analyzer"); myWindow.setSize(500, 200); myWindow.setVisible(true); } // Class constructor. public App(String title) { // Usual boilerplate for startup and shutdown. super(title); addWindowListener( new WindowAdapter() { public void windowClosing(WindowEvent e) { dispose(); System.exit(0); } } ); // Create the frame's menu bar. mainBar = new MenuBar(); setMenuBar(mainBar); fileMenu = new Menu("File"); find = new MenuItem("Find"); find.addActionListener(this); fileMenu.add(find); fileMenu.addSeparator(); exit = new MenuItem("Exit"); exit.addActionListener(this); fileMenu.add(exit); mainBar.add(fileMenu); // Create the file information text area. fileInfo = new TextArea(" Use the menu bar to find a file...", 10, 40, TextArea.SCROLLBARS_NONE); fileInfo.setFont(new Font("Monospaced", Font.PLAIN, 12)); fileInfo.setEditable(false); add(fileInfo); } // Required method of the ActionListener interface. public void actionPerformed(ActionEvent e) { // If the user selected "File" | "Find" from the menu, let them // choose a file to be analyzed. Then, display its information. if (e.getSource().equals(find)) { // Create and display a modal file dialog box through which the // user can choose the file they want to analyze. FileDialog fd = new FileDialog(this, "Choose file", FileDialog.LOAD); fd.setVisible(true); // Construct a File object for the file the user selected. File f = new File(fd.getDirectory() + File.separator + fd.getFile()); // Display information about the file the user selected. fileInfo.setText(" FILE INFORMATION "); fileInfo.append(" Path: " + f.getPath()); fileInfo.append(" Directory: " + fd.getDirectory()); fileInfo.append(" File: " + f.getName()); fileInfo.append(" Last modified: " + new Date(f.lastModified()).toString()); fileInfo.append(" Byte length: " + f.length()); fileInfo.setCaretPosition(0); } // If the user selected "File" | "Exit" from the menu, terminate // the application. if (e.getSource().equals(exit)) { dispose(); System.exit(0); } } |
While the File and FileDialog classes allow a program to act upon the file structure of a platform, they do NOT allow for the actual storage and retrieval of data. That is covered in the next article.
In the previous article, you learned how to uses Java's I/O streams to write data to disk and read data from disk. In both cases, the organization of the file was sequential. All file data was written or read one item after another.
Sequential files are useful, but they do not provide a way to quickly locate an item of data without reading through all the other items of data that precede it. They also do not provide a means of updating an item of data without copying the entire file.
In this article, you will learn the essentials of Java's RandomAccessFile class, which permits a program to directly access an item of data and replace its contents.
The RandomAccessFile class
· Is part of the java.io package
· Is an extension of the Object class. It does NOT descend from the InputStream or OutputStream classes.
Object
RandomAccessFile
· Is a high-level class that can be used to directly read or write primitive data items and UTF strings to a file. The file behaves like a large array of bytes. By positioning a pointer ("seeking") to a byte location within the file, a particular item of data may be either read or written.
· Has two constructors. The most frequently used requires two parameters
1. The reference of a File object that contains the pathname of the file.
2. A String that represents the mode of access. It must be either "r" (read only) or "rw" (read/write).
For example, if fd is the reference of a File object
RandomAccessFile raf = new RandomAccessFile(fd, "rw");
will construct a RandomAccessFile object for both reading and writing primitive values and UTF strings to the file. Because a checked, IOException may occur, the statement should be enclosed in a try block with an appropriate catch.
· Has many useful methods as follows:
| Method | Usage |
| getFilePointer() | Returns the byte offset of the pointer into this file |
| length() | Returns the byte length of this file |
| readBoolean() | Reads a boolean value from the pointer location within the file |
| readByte() | Reads a byte value from the pointer location within the file |
| readChar() | Reads a char value from the pointer location within the file |
| readDouble() | Reads a double value from the pointer location within the file |
| readFloat() | Reads a float value from the pointer location within the file |
| readInt() | Reads a int value from the pointer location within the file |
| readLong() | Reads a long value from the pointer location within the file |
| readShort() | Reads a short value from the pointer location within the file |
| readUTF() | Reads a String from the pointer location within the file according to the UTF standard |
| seek() | Sets the pointer offset, measured from the beginning of this file, at which the next read or write will occur |
| writeBoolean() | Writes a specified boolean value to the pointer location within the file |
| writeByte() | Writes a specified byte value to the pointer location within the file |
| writeChar() | Writes a specified char value to the pointer location within the file |
| writeDouble() | Writes a specified double value to the pointer location within the file |
| writeFloat() | Writes a specified float value to the pointer location within the file |
| writeInt() | Writes a specified int value to the pointer location within the file |
| writeLong() | Writes a specified long value to the pointer location within the file |
| writeShort() | Writes a specified short value to the pointer location within the file |
| writeUTF() | Writes a specified String to the pointer location within the file according to the UTF standard |
Notes:
1. All read and write methods automatically advance the pointer to the next data item within the file.
2. Because a checked, IOException may occur, calls to these methods should be enclosed in a try block with an appropriate catch. Consult the Java API documentation for more details.
· Example. The following program creates a file of 100 integers. The user is then allowed to directly read and change the value of selected integers within the file. The final contents of the file are then displayed.
| import java.io.*; public class App { public static void main(String[] args) { // Local variables and object references. File fd; // Get the path name from the user. System.out.print("Enter the file's complete path name: "); fd = new File(Keyboard.readString()); // Try to process the file. try { // Format the file with 100 integer values (all zero). DataOutputStream out = new DataOutputStream(new FileOutputStream(fd)); for (int i = 0; i < 100; i++) { out.writeInt(0); } out.close(); System.out.println("The file is formatted with 100 integers"); // Re-open the file for random reading and writing. RandomAccessFile raf = new RandomAccessFile(fd, "rw"); // Allow the user to see and change any integer value within // the file. char again; do { // Ask the user for the integer's position within the file. System.out.print("Specify an integer's position (0 to 99): "); int position = Keyboard.readInt(); // Calculate the integer's offset (byte displacement) within // the file. int pointer = position * 4; // If the offset is valid, locate the integer, read and display // its current value, get a new value from the user, and write // the new value back to the same location within the file. if (pointer < raf.length()) { raf.seek(pointer); System.out.println("Current value: " + raf.readInt()); raf.seek(pointer); System.out.print("New value: "); raf.writeInt(Keyboard.readInt()); } // If the offset is not valid, display an error message. else { System.out.println("Invalid position"); } // Ask the user if they want to change another integer value // and repeat the loop as requested. System.out.print("Change another value? (Y/N) "); again = Keyboard.readChar(); } while (again == 'Y' || again == 'y'); // Close the random access file. raf.close(); // Re-open the file for sequential input and display the // file's contents. DataInputStream in = new DataInputStream(new FileInputStream(fd)); try { int position = 0; while (true) { System.out.println(position + ": " + in.readInt()); position++; } } catch (EOFException e) { System.out.println(""); } in.close(); System.out.println("Closed - " + fd.getPath()); } // Catch an IOException if one is thrown. catch (IOException e) { System.out.println(e.getMessage()); } } } |
Limitations and solutions
The usefulness of the RandomAccessFile class is severely restricted by its inability to read and write objects. For example, it would be difficult to use a RandomAccessFile to process a file of Customer objects.
The simplest solution to this problem is to use a Map collection (such as a HashMap) for the objects. All collections are serializable. In a single I/O operation, the entire Map can be written to disk using an ObjectOutputStream or read from disk using an ObjectInputStream. The get() and put() methods can be used to access the collection's objects while the Map is in memory.
The author you can reach on dineshnair@hotmail.com
Language: Java
Platform: Independent
