需求:文件存儲多個對象,讀取其中一個、修改後寫回原位置。C 語言用 fseek 控制文件指針,Java 中用 RandomAccessFile 實現隨機訪問。
| 方法 | 說明 |
|---|---|
seek(long pos) | 移動文件指針到指定字節偏移量 |
getFilePointer() | 獲取當前指針位置 |
readInt()/writeInt() | 讀寫基本類型(4 字節) |
readUTF()/writeUTF() | 讀寫修改版 UTF-8 字符串 |
length() | 獲取文件長度 |
public class RandomAccessDemo {
// 假設對象結構:int id(4B) + UTF name(變長) + double score(8B)
// 為了定位,需要知道每條記錄的起始位置 → 建立索引或固定長度
// 方案一:固定長度記錄(簡單、隨機訪問快)
static final int RECORD_SIZE = 4 + 32 + 8; // id(4) + name(32固定) + score(8) = 44 字節
public static void updateNameByIndex(String filePath, int index, String newName) throws IOException {
try (RandomAccessFile raf = new RandomAccessFile(filePath, "rw")) {
long pos = (long) index * RECORD_SIZE;
raf.seek(pos);
int id = raf.readInt(); // 讀取 id(可選驗證)
raf.seek(pos + 4); // 跳過 id,定位到 name 起始
// 寫入固定長度 name:不足補空格,超出截斷
byte[] nameBytes = newName.getBytes(StandardCharsets.UTF_8);
byte[] fixedName = new byte[32];
System.arraycopy(nameBytes, 0, fixedName, 0, Math.min(nameBytes.length, 32));
raf.write(fixedName);
System.out.println("更新完成:索引 " + index + " 的 name → " + newName);
}
}
// 方案二:變長記錄 + 索引文件(節省空間、適合大文件)
// 主文件:順序存儲對象
// 索引文件:每條記錄 8 字節 (long offset) → 隨機訪問索引獲取偏移量
}
ReentrantLock 或 FileChannel.lock())seek 超過文件末尾再寫入會自動擴展文件(中間填 0)| 方案 | 優點 | 缺點 | 適用場景 |
|---|---|---|---|
| RandomAccessFile | 真隨機訪問、不載入內存、支持大文件 | 需手動管理結構、無緩衝、併發難 | 固定結構、頻繁隨機修改、大文件 |
| 全部讀入內存修改再寫回 | 代碼簡單、支持任意結構 | 大文件 OOM、修改慢 | 小文件、結構複雜、修改頻率低 |
| SQLite / H2 內嵌數據庫 | SQL 查詢、事務、索引、併發 | 引入依賴、有開銷 | 結構變化大、需查詢、多線程 |
| MemoryMappedFile (FileChannel.map) | OS 級映射、極快、大文件友好 | 映射大小固定、擴展麻煩 | 超大文件、高性能讀寫 |
簡單場景用 RandomAccessFile 固定長度記錄 最直接;複雜業務上 SQLite 更省心。