18.7. (Optional) Random Access Files |
All of the streams you have used so far are known as read-only or write-only streams. The external files of these streams are sequential files that cannot be updated without creating a new file. It is often necessary to modify files or to insert new records into files. Java provides the RandomAccessFile class to allow a file to be read from and written to at random locations.
The RandomAccessFile class implements the DataInput and DataOutput interfaces, as shown in Figure 18.16. The DataInput interface shown in Figure 18.9 defines the methods (e.g., readInt , readDouble , readChar , readBoolean , readUTF ) for reading primitive type values and strings, and the DataOutput interface shown in Figure 18.10 defines the methods (e.g., writeInt , writeDouble , writeChar , writeBoolean , writeUTF ) for writing primitive type values and strings.
When creating a RandomAccessFile , you can specify one of two modes ( "r" or "rw" ). Mode "r" means that the stream is read-only, and mode "rw" indicates that the stream allows both read and write. For example, the following statement creates a new stream, raf , that allows the program to read from and write to the file test.dat :
RandomAccessFile raf = new RandomAccessFile( "test.dat" , "rw" );
If test.dat already exists, raf is created to access it; if test.dat does not exist, a new file named test.dat is created, and raf is created to access the new file. The method raf.length() returns the number of bytes in test.dat at any given time. If you append new data into the file, raf.length() increases .
Tip
Open the file with the "r" mode if the file is not intended to be modified. This prevents unintentional modification of the file. |
A random access file consists of a sequence of bytes. There is a special marker called file pointer that is positioned at one of these bytes. A read or write operation takes place at the location of the file pointer. When a file is opened, the file pointer is set at the beginning of the file. When you read or write data to the file, the file pointer moves forward to the next data item. For example, if you read an int value using readInt() , the JVM reads 4 bytes from the file pointer and now the file pointer is 4 bytes ahead of the previous location, as shown in Figure 18.17.
For a RandomAccessFile raf , you can use raf.seek(position) method to move the file pointer to a specified position. raf.seek(0) moves it to the beginning of the file, and raf.seek(raf.length()) moves it to the end of the file. Listing 18.7 demonstrates RandomAccessFile .
1 import java.io.*; 2 3 public class TestRandomAccessFile { 4 public static void main(String[] args) throws IOException { 5 // Create a random access file 6 RandomAccessFile inout = new RandomAccessFile( "inout.dat" , "rw"); 7 8 // Clear the file to destroy the old contents if exists 9 inout.setLength( ); 10 11 // Write new integers to the file 12 for ( int i = ; i < 200 ; i++) 13 inout.writeInt(i); 14 15 // Display the current length of the file 16 System.out.println( "Current file length is " + inout.length() ); 17 18 // Retrieve the first number 19 inout.seek( ); // Move the file pointer to the beginning 20 System.out.println( "The first number is " + inout.readInt() ); 21 22 // Retrieve the second number 23 inout.seek( 1 * 4 ); // Move the file pointer to the second number 24 System.out.println( "The second number is " + inout.readInt() ); 25 26 // Retrieve the tenth number 27 inout.seek( 9 * 4 ); // Move the file pointer to the tenth number 28 System.out.println( "The tenth number is " + inout.readInt() ); 29 30 // Modify the eleventh number 31 inout.writeInt( 555 ); 32 33 // Append a new number 34 inout.seek(inout.length()); // Move the file pointer to the end 35 inout.writeInt( 999 ); 36 37 // Display the new length 38 System.out.println( "The new length is " + inout.length() ); 39 40 // Retrieve the new eleventh number 41 inout.seek( 10 * 4 ); // Move the file pointer to the eleventh number 42 System.out.println( "The eleventh number is " + inout.readInt() ); 43 44 inout.close(); 45 } 46 } |
A RandomAccessFile is created for the file named inout.dat with mode " rw " to allow both read and write operations in line 6.
inout.setLength(0) sets the length to in line 9. This, in effect, destroys the old contents of the file.
The for loop writes two hundred int values from to 199 into the file in lines 12 “13. Since each int value takes 4 bytes, the total length of the file returned from inout.length() is now 800 (line 16), as shown in Figure 18.18.
Invoking inout.seek(0) in line 19 sets the file pointer to the beginning of the file. inout.readInt() reads the first value in line 20 and moves the file pointer to the next number. The second number is read in line 24.
inout.seek(9 * 4) (line 27) moves the file pointer to the tenth number. inout.readInt() reads the tenth number and moves the file pointer to the eleventh number in line 28. inout.write(555) writes a new eleventh number at the current position (line 31). The previous eleventh number is destroyed .
inout.seek(inout.length()) moves the file pointer to the end of the file (line 34). inout.writeInt(999) writes 999 to the file. Now the length of the file is increased by 4, so inout.length() returns 804 (line 38).
inout.seek(10 * 4) moves the file pointer to the eleventh number in line 41. The new eleventh number, 555, is displayed in line 42.