The RandomAccessFile class enables both reading and writing to files, offering the capability to jump directly to any location within a file for data access. This feature makes it ideal for scenarios where only specific parts of a file need to be acecssed rather than reading the entire file sequentially.
Different from standard output streams like OutputStream or Writer, RandomAccessFile allows manipulation of the file pointer's position, enabling operations such as appending data to an existing file. This characteristic makes it particularly suitable when you intend to add data to a file that already contains information.
Although RandomAccessFile provides a rich set of methods, its primary limitation is that its restricted to file-based operations only and cannot interact with other I/O sources.
An important application of RandomAccessFile is in implementing multi-threaded downloads and resume functionality in network requests.
// Retrieve current file pointer position (initially at 0) System.out.println("Initial file pointer position: " + raf.getFilePointer());
// Move file pointer to a specific location raf.seek(position);
// Read data into buffer byte[] buffer = new byte[1024]; int bytesRead;
while ((bytesRead = raf.read(buffer)) > 0) { // Output the content System.out.println(new String(buffer, 0, bytesRead)); }
</div>### Example: Implementing Create, Read, Update, Delete with RandomAccessFile
#### Utility Class Setup
Encapsulate the various modes of `RandomAccessFile` and define the target file path:
<div>```
public class RAFUtil {
private static final String filePath = "test.txt";
private static final String[] modes = {"r", "rw", "rws", "rwd"};
public static RandomAccessFile getFileReader() throws FileNotFoundException {
return new RandomAccessFile(new File(filePath), modes[0]);
}
public static RandomAccessFile getFileWriter() throws FileNotFoundException {
return new RandomAccessFile(new File(filePath), modes[1]);
}
public static RandomAccessFile getFileReadWriteSync() throws FileNotFoundException {
return new RandomAccessFile(new File(filePath), modes[2]);
}
public static RandomAccessFile getFileReadWriteDirect() throws FileNotFoundException {
return new RandomAccessFile(new File(filePath), modes[3]);
}
}
The entity class must implement Serializable:
private int id; // 4 bytes
private String name;
private double price; // 8 bytes
public Project() {}
public Project(int id, String name, double price) {
this.id = id;
this.name = (name != null) ?
String.format("%-15s", name).substring(0, 15) :
String.format("%-15s", "").substring(0, 15);
this.price = price;
}
public int getId() { return id; }
public void setId(int id) { this.id = id; }
public String getName() { return name; }
public void setName(String name) { this.name = name; }
public double getPrice() { return price; }
public void setPrice(double price) { this.price = price; }
public static int size() {
return 4 + 8 + 30; // id + price + name (fixed length)
}
@Override
public String toString() {
return "Project{id=" + id + ", name='" + name + "', price=" + price + "}";
}
}
</div>#### CRUD Operations Implementation
<div>```
public class FileOperations {
public void insert(Project project) throws IOException {
RandomAccessFile raf = RAFUtil.getFileWriter();
raf.seek(raf.length()); // Go to end of file
raf.writeInt(project.getId());
raf.writeChars(project.getName());
raf.writeDouble(project.getPrice());
raf.close();
System.out.println("Project inserted successfully.");
}
public Project read(int index) throws IOException {
RandomAccessFile raf = RAFUtil.getFileReader();
raf.seek((index - 1) * Project.size());
Project p = new Project();
p.setId(raf.readInt());
p.setName(readFixedString(raf, 15));
p.setPrice(raf.readDouble());
raf.close();
System.out.println("Project read successfully.");
System.out.println(p);
return p;
}
public void remove(int index) throws IOException {
RandomAccessFile raf = RAFUtil.getFileWriter();
long offset = (index - 1) * Project.size();
raf.seek(offset);
// Shift all subsequent entries up
byte[] buffer = new byte[1024];
int bytesRead;
long pos = offset + Project.size();
while ((bytesRead = raf.read(buffer, 0, Math.min(buffer.length, (int)(raf.length() - pos)))) > 0) {
raf.seek(pos - Project.size());
raf.write(buffer, 0, bytesRead);
pos += bytesRead;
}
// Truncate the file to remove leftover data
raf.setLength(pos - Project.size());
raf.close();
System.out.println("Project deleted.");
}
public void update(int index, Project project) throws IOException {
remove(index);
project.setId(index);
insert(project);
System.out.println("Project updated successfully.");
}
private String readFixedString(RandomAccessFile raf, int length) throws IOException {
char[] chars = new char[length];
for (int i = 0; i < length; i++) {
chars[i] = raf.readChar();
}
return new String(chars).trim();
}
}