| 模式 | 建構式 | 說明 |
| 唯讀 | new RandomAccessFile(file, "r")僅允許讀取,檔案必須存在 |
| 讀寫 | new RandomAccessFile(file, "rw")讀寫皆可,檔案不存在則建立 |
| 讀寫同步 | new RandomAccessFile(file, "rws")內容與中繼資料同步寫入磁碟 |
| 讀寫內容同步 | new RandomAccessFile(file, "rwd")僅內容同步,效能較佳 |
關鍵 API 分類
- 指標控制:
getFilePointer()、seek(long pos)、skipBytes(int n)
- 基本型別讀寫:
readInt()/writeInt()、readLong()/writeLong()、readDouble()/writeDouble() 等
- 字元/字串處理:
readChar()/writeChar() (UTF-16, 2 bytes)、readUTF()/writeUTF() (修改版 UTF-8)、readLine()
- 位元組陣列:
read(byte[] b)/write(byte[] b)、read(byte[] b, int off, int len)
- 檔案長度:
length()、setLength(long newLength)
三階段進階範例:員工記錄隨機存取
階段 1:基本位元組操作 (僅 ASCII)
public class Employee {
public static final int NAME_BYTES = 8; // 固定 8 bytes
private String name;
private int age;
// 建構子自動截斷/補齊 name 至 8 bytes
}
RandomAccessFile raf = new RandomAccessFile("emp.dat", "rw");
// 寫入
raf.write(e1.name.getBytes()); // 8 bytes
raf.writeInt(e1.age); // 4 bytes
raf.write(e2.name.getBytes());
raf.writeInt(e2.age);
// 讀取:skipBytes(12) 定位第 2 筆 (8+4=12)
raf.seek(0); // 第 1 筆
raf.skipBytes(12); // 第 2 筆
階段 2:支援大數值 (writeInt/readInt)
年齡欄位改用 writeInt/readInt (4 bytes),固定記錄長度 = 8 + 4 = 12 bytes。定位公式:recordIndex * RECORD_SIZE。
階段 3:完整支援中文字元 (writeChars/readChar)
// 寫入:每個 char (含中文) 佔 2 bytes
raf.writeChars(e1.name); // 8 chars × 2 = 16 bytes
raf.writeInt(e1.age); // 4 bytes
// RECORD_SIZE = 16 + 4 = 20 bytes
// 讀取:逐字元讀取
StringBuilder sb = new StringBuilder();
for (int i = 0; i < Employee.NAME_CHARS; i++) {
sb.append(raf.readChar());
}
String name = sb.toString().trim();
int age = raf.readInt();
關鍵差異:getBytes() 依平台編碼 (中文 2-3 bytes),writeChars() 固定 UTF-16 (2 bytes/char),適合固定長度記錄。
實戰陷阱與最佳實踐
| 陷阱 | 解決方案 |
| 編碼不一致導致讀取亂碼 | 統一使用 writeChars/readChar (UTF-16) 或 writeUTF/readUTF (長度前綴) |
| 記錄長度不固定無法隨機定位 | 定義固定長度結構,字串欄位補齊/截斷 |
| 並發存取資料損毀 | 單執行緒存取或外部鎖 (FileLock/ReentrantLock) |
| 大檔案記憶體壓力 | 分塊讀寫、MappedByteBuffer (NIO) |
| 未關閉資源洩漏 | try-with-resources (Java 7+) 確保關閉 |
進階替代方案:NIO MappedByteBuffer
FileChannel channel = FileChannel.open(Paths.get("big.dat"), READ, WRITE);
MappedByteBuffer buffer = channel.map(FileChannel.MapMode.READ_WRITE, 0, fileSize);
// 直接記憶體映射,OS 負責分頁,適合 GB 級大檔案隨機存取
結語
RandomAccessFile 是處理固定結構二進位檔案的利器。掌握指標控制、編碼選擇、記錄定位算法,即可高效實作索引檔案、緩存系統、嵌入式資料庫等場景。現代專案建議優先評估 NIO Memory-Mapped Files 或嵌入式資料庫 (H2/SQLite) 以獲得更豐富功能。
- 上一篇文章: Hibernate 3 Annotations 進階實戰:從 XML 到註解的持久化映射革命
- 下一篇文章: 硬回車、軟回車與 Java 轉義字元完整對照表
Copyright ©
程式碼之家 All Rights Reserved