Random Access Files
Overview
Random access files permit nonsequential, or random, access to a file's contents. Rather than going through an entire file sequentially to find a record, random access files offer a seek feature that allows one to go directly to a particular position.The java.io.RandomAccessFile class implements a random access file.
Unlike the input and output stream classes in java.io, RandomAccessFile is used for both reading and writing files. You create a RandomAccessFile object with different arguments depending on whether you intend to read or write.
RandomAccessFile does not inherit from InputStream or OutputStream. However, it does implement the DataInput and DataOutput interfaces.
Using Random Access Files
RandomAccessFile is similar to FileInputStream and FileOutputStream in that you specify a file on the native file system to open when you create it. You can do this with a file name or a File object.
Here is an example of opening a file read only:
new RandomAccessFile("farrago.txt", "r");And this one opens the same file for both reading and writing:
new RandomAccessFile("farrago.txt", "rw");After the file has been opened, you can use the common read or write methods defined in the DataInput and DataOutput interfaces to perform I/O on the file.
RandomAccessFile supports the notion of a file pointer, which indicates the current location in the file. When the file is first created, the file pointer is set to 0, indicating the beginning of the file. Calls to the read and write methods adjust the file pointer by the number of bytes read or written.
In addition to the normal file I/O methods that implicitly move the file pointer when the operation occurs, RandomAccessFile contains three methods for explicitly manipulating the file pointer.
top>int skipBytes(int) Moves the file pointer forward the specified number of bytes top>void seek(long) Positions the file pointer just before the specified byte long getFilePointer() Returns the current byte location of the file pointer
Writing Filters
Let's rewrite the example from Filter Streams so that it works on RandomAccessFiles. The example CheckedIODemo.java from Filter Streams implements two filter streams that compute a checksum as data is read from or written to the stream. Those streams are CheckedInputStream.java and CheckedOutputStream.java.
In the new example, CheckedDataOutput.java is a rewrite of CheckedOutputStream.java, it computes a checksum for data writen to the stream. However, it operates on DataOutput objects instead of on OutputStream objects. Similarly, CheckedDataInput.java modifies CheckedInputStream.java so that it now works on DataInput objects instead of InputStream objects.
 
CheckedDataOutput versus CheckedOutputStream
Let's look at how CheckedDataOutput.java differs from CheckedOutputStream.java.The first difference in these two classes is that CheckedDataOutput.java does not extend FilterOutputStream. Instead, it implements the DataOutput interface.
public class CheckedDataOutput implements DataOutputTo keep the example code simple, the CheckedDataOutput.java class actually provided in this lesson is not declared to implement DataOutput, because the DataOutput interface specifies so many methods. However, the CheckedDataOutput.java class as provided in the example does implement several of DataOutput's methods to illustrate how it should work.
Next, CheckedDataOutput.java declares a private variable to hold a DataOutput object.
This is the object to which data will be written.private DataOutput out;The constructor for CheckedDataOutput.java differs from CheckedOutputStream.java's constructor in that CheckedDataOutput.java 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.java constructor did, because CheckedDataOutput.java extends from Object rather than from a stream class.
Those are the only modifications made to CheckedOutputStream.java to create a filter that works on DataOutput objects.
CheckedDataInput versus CheckedInputStream
CheckedDataInput.java requires the same changes as CheckedDataOutput.java, as follows:
- CheckedDataInput.java does not derive from FilterInputStream. Instead, it implements the DataInput interface instead.
- CheckedDataInput.java declares a private variable to hold a DataInput object, which it wraps.
- The constructor for CheckedDataInput.java requires a DataInput object rather than an InputStream.
In addition to these changes, the read methods are changed. CheckedInputStream.java 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.java 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:
- CheckedDIDemo.java, which runs the filters on sequential access files.
- CheckedRAFDemo.java, which runs the filters on random access files.
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:
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 DataInputStream(new FileInputStream("farrago.txt")), inChecker); out = new CheckedDataOutput(new DataOutputStream(new FileOutputStream("outagain.txt")), outChecker);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
![]()