The JavaTM Tutorial
Previous Page Lesson Contents Next Page Start of Tutorial > Start of Trail > Start of Lesson Search
Feedback Form

Trail: Essential Java Classes
Lesson: I/O

Writing Filters for Random Access Files

Let's rewrite the example from How to Write Your Own Filter Streams so that it works on RandomAccessFiles. Because RandomAccessFile implements the DataInput (in the API reference documentation) and DataOutput (in the API reference documentation) interfaces, a side benefit is that the filtered stream will also work with other DataInput and DataOutput streams including some sequential access streams such as DataInputStream and DataOutputStream.

The example CheckedIODemo (in a .java source file) from How to Write Your Own Filter Streams implements two filter streams that compute a checksum as data is read from or written to the stream. Those streams are CheckedInputStream (in a .java source file) and CheckedOutputStream (in a .java source file).

In the new example, CheckedDataOutput (in a .java source file) is a rewrite of CheckedOutputStream--it computes a checksum for data writen to the stream. However, it operates on DataOutput objects instead of on OutputStream objects. Similarly, CheckedDataInput (in a .java source file) modifies CheckedInputStream so that it now works on DataInput objects instead of InputStream objects.

CheckedDataOutput versus CheckedOutputStream

Let's look at how CheckedDataOutput differs from CheckedOutputStream.

The first difference in these two classes is that CheckedDataOutput does not extend FilterOutputStream. Instead, it implements the DataOutput interface.

public class CheckedDataOutput implements DataOutput


Note:  To keep the example code simple, the CheckedDataOutput class actually provided in this lesson is not declared to implement DataOutput, because the DataOutput interface specifies so many methods. However, the CheckedDataOutput class as provided in the example does implement several of DataOutput's methods to illustrate how it should work.

Next, CheckedDataOutput declares a private variable to hold a DataOutput object.

private DataOutput out;
This is the object to which data will be written.

The constructor for CheckedDataOutput differs from CheckedOutputStream's constructor in that CheckedDataOutput is created on a DataOutput object rather than on an OutputStream.

public CheckedDataOutput(DataOutput out, Checksum cksum) {
    this.cksum = cksum;
    this.out = out;
}
This constructor does not call super(out) like the CheckedOutputStream constructor did, because CheckedDataOutput extends from Object rather than from a stream class.

Those are the only modifications made to CheckedOutputStream to create a filter that works on DataOutput objects.

CheckedDataInput versus CheckedInputStream

CheckedDataInput requires the same changes as CheckedDataOuput, as follows: In addition to these changes, the read methods are changed. CheckedInputStream from the original example implements two read methods, one for reading a single byte and one for reading a byte array. The DataInput interface has methods that implement the same functionality, but they have different names and different method signatures. Thus, the read methods in the CheckedDataInput class have new names and method signatures:
public byte readByte() throws IOException {
    byte b = in.readByte();
    cksum.update(b);
    return b;
}

public void readFully(byte[] b) throws IOException {
    in.readFully(b, 0, b.length);
    cksum.update(b, 0, b.length);
}

public void readFully(byte[] b, int off, int len) throws IOException {
    in.readFully(b, off, len);
    cksum.update(b, off, len);
}
Also, the DataInput interface declares many other methods that we don’t implement for this example.

The Main Programs

Finally, this example has two main programs to test the new filters: These two main programs differ only in the type of object they open the checksum filters on. CheckedDIDemo creates a DataInputStream and a DataOutputStream and uses the checksum filter on them, as in the following code:
in = new CheckedDataInput(new DataInputStream(
         new FileInputStream("farrago.txt")), inChecker);
out = new CheckedDataOutput(new DataOutputStream(
          new FileOutputStream("outagain.txt")), outChecker);
CheckedRAFDemo creates two RandomAccessFile objects: one for reading and one for writing. It uses the checksum filter on them as follows:
in = new CheckedDataInput(
         new RandomAccessFile("farrago.txt", "r"), inChecker);
out = new CheckedDataOutput(
          new RandomAccessFile("outagain.txt", "rw"), outChecker);

When you run either of these programs you should see the following output:

Input stream check sum: 736868089
Output stream check sum: 736868089

Previous Page Lesson Contents Next Page Start of Tutorial > Start of Trail > Start of Lesson Search
Feedback Form

Copyright 1995-2005 Sun Microsystems, Inc. All rights reserved.