An introduction to I/O and the File and FileDialog classes in 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




Added on August 3, 2007 Comment

Comments

Post a comment

Your name:

Comment: