Random-Access Files

File input and output streams require you to start reading or writing at the beginning of a file and then read or write the file in order, possibly skipping over some bytes or backing up but mostly moving from start to finish. Sometimes, however, you need to read parts of a file in a more or less random order, where the data near the beginning of the file isn't necessarily read before the data nearer the end. Other times you need to both read and write the same file. For example, in record-oriented applications like databases, the actual data may be indexed; you would use the index to determine where in the file to find the record you need to read or write. While you could do this by constantly opening and closing the file and skipping to the point where you needed to read, this is far from efficient. Writes are even worse since you would need to read and rewrite the entire file, even to change just one byte of data.

Random-access files can be read from or written to or both from a particular byte position in the file. A single random-access file can be both read and written. The position in the file where reads and writes start from is indicated by an integer called the file pointer. Each read or write advances the file pointer by the number of bytes read or written. Furthermore, the programmer can reposition the file pointer at different bytes in the file without closing the file.

In Java, random file access is performed through the java.io.RandomAccessFile class. This is not a subclass of java.io.File:

The first argument to the constructor is the file you want to access. The second argument is the mode for access. The mode can be "r" for read-only access or "rw", "rws", or "rwd" for read/write access. Java does not support write-only access. For example:

RandomAccessFile raf = new RandomAccessFile("29.html", "r");

The rw mode is regular buffered read-write access. Changes may not be immediately written to the file. This can lose data in the event of a system crash. In rws mode, Java writes all data to the disk immediately and is safer if slower. In rwd mode, Java writes all content immediately but may buffer changes to the file's metadata (its name, permissions, and so on).

An IllegalArgumentException is thrown if anything other than these four strings is specified as the mode. (In Java 1.3 and earlier, only "rw" and "r" were allowed.) A security exception is thrown if the security manager does not allow the requested file to be read. A security exception is also thrown if you request read/write access, but only read access is allowed. Security checks are made only when the object is constructed. It is assumed that the security manager's policy won't change while the program is running. Finally, an IOException is thrown if the operating system doesn't allow the file to be accessed or some other I/O problem occurs.

The getFilePointer( ) and seek( ) methods allow you to query and change the position in the file at which reads and writes occur. Attempts to seek (position the file pointer) past the end of the file just move the file pointer to the end of the file. Attempts to write from the end of the file extend the file.

Attempts to read from the end of the file throw an EOFException (a subclass of IOException). You can determine the length of the file with the length( ) method:

public native long length( ) throws IOException

The RandomAccessFile class implements both the DataInput and DataOutput interfaces. Therefore, reads and writes use methods exactly like the methods of the DataInputStream and DataOutputStream classes, such as read( ), readFully( ), readInt( ), writeInt( ), readBoolean( ), writeBoolean( ), and so on.

Finally, there are a few miscellaneous methods. The getFD( ) method simply returns the file descriptor for this file:

public final FileDescriptor getFD( ) throws IOException

The skipBytes( ) method attempts to reposition the file pointer n bytes further in the file from where it is now. It returns the number of bytes actually skipped, which may be less than n:

public int skipBytes(int n) tHRows IOException

The seek( ) method jumps to an absolute position in the file starting from 0, whereas skipBytes( ) moves n bytes past wherever the file pointer is now:

public void seek(long position) throws IOException

Finally, the close( ) method closes the file:

public native void close( ) throws IOException

Once the file is closed, it may not be read from, though a new RandomAccessFile object that refers to the same file can be created.