RandomAccessFile 是 Java IO 體系中獨特的存在:它不屬於流體系(不繼承 InputStream/OutputStream),而是直接繼承 Object 並實現 DataInput、DataOutput 接口。其核心優勢在於隨機訪問——可將文件指針移動到任意位置進行讀寫,適合處理固定長度記錄的文件(如數據庫索引、二進制日誌)。
| 構造方法 | 說明 |
|---|---|
RandomAccessFile(File file, String mode) | 基於 File 對象 |
RandomAccessFile(String name, String mode) | 基於路徑字符串 |
mode 參數:
"r":只讀模式"rw":讀寫模式(最常用)"rws" / "rwd":同步寫入(元數據/數據同步到磁盤)| 方法 | 功能 |
|---|---|
void seek(long pos) | 移動文件指針到指定位置(字節偏移量) |
long getFilePointer() | 獲取當前指針位置 |
long length() | 獲取文件長度 |
int skipBytes(int n) | 跳過 n 個字節,返回實際跳過數 |
void writeBytes(String s) | 寫入字符串的低八位(每字符一字節) |
void writeInt(int v) | 寫入 4 字節整數(高位在前) |
byte readByte() | 讀取一個有符號字節 |
int readInt() | 讀取 4 字節整數 |
int read(byte[] b) | 批量讀取到字節數組 |
void close() | 關閉文件,釋放資源 |
假設每條記錄結構:姓名 8 字節(不足補空格)+ 年齡 4 字節 int = 12 字節/條。
public class RandomAccessFileDemo {
private static final String FILE_PATH = "G:" + File.separator + "JavaTest" + File.separator + "records.dat";
private static final int RECORD_SIZE = 12; // 8 + 4
public static void main(String[] args) throws IOException {
// 1. 寫入三條記錄
writeRecords();
// 2. 隨機讀取第 2 條記錄(索引 1)
readRecord(1);
// 3. 修改第 1 條記錄的年齡
updateAge(0, 25);
// 4. 驗證修改
readRecord(0);
}
static void writeRecords() throws IOException {
try (RandomAccessFile raf = new RandomAccessFile(FILE_PATH, "rw")) {
writeRecord(raf, "liuyan ", 40);
writeRecord(raf, "xiaoming", 30);
writeRecord(raf, "doudou ", 24);
}
}
static void writeRecord(RandomAccessFile raf, String name, int age) throws IOException {
raf.writeBytes(name); // 8 字節
raf.writeInt(age); // 4 字節
}
static void readRecord(int index) throws IOException {
try (RandomAccessFile raf = new RandomAccessFile(FILE_PATH, "r")) {
raf.seek(index * RECORD_SIZE);
byte[] nameBytes = new byte[8];
raf.readFully(nameBytes); // 確保讀滿 8 字節
String name = new String(nameBytes).trim();
int age = raf.readInt();
System.out.printf("第 %d 條:姓名=%s,年齡=%d%n", index + 1, name, age);
}
}
static void updateAge(int index, int newAge) throws IOException {
try (RandomAccessFile raf = new RandomAccessFile(FILE_PATH, "rw")) {
raf.seek(index * RECORD_SIZE + 8); // 跳過姓名,定位到年齡
raf.writeInt(newAge);
System.out.println("已更新第 " + (index + 1) + " 條記錄年齡為 " + newAge);
}
}
}
seek 計算偏移量會出錯。writeBytes 只寫低 8 位,中文會截斷。實際項目建議使用 writeChar(2 字節/字符)或預先編碼為定長字節數組(如 UTF-8 定長填充)。read(byte[]) 可能讀不滿數組,關鍵數據務必用 readFully 保證讀滿。RandomAccessFile 非線程安全,多線程環境需自行加鎖或使用 NIO FileChannel。finally 或 try-with-resources 中調用 close(),否則文件鎖可能不釋放。| 特性 | RandomAccessFile | FileInputStream/FileOutputStream | NIO FileChannel |
|---|---|---|---|
| 隨機訪問 | ✅ 原生支持 | ❌ 僅順序 | ✅ position() |
| 讀寫模式 | 單對象雙向 | 分離雙流 | Channel 雙向 |
| 線程安全 | ❌ | ❌ | ✅ (配合鎖) |
| 性能(大文件) | 中等 | 較低 | 高 (零拷貝) |
| 適用場景 | 固定長度記錄、小型嵌入式數據庫 | 流式讀寫 | 高性能、大文件、網絡傳輸 |