RandomAccessFile 是 Java IO 體系中獨特的存在——它同時支援檔案的讀取與寫入,且能夠隨機定位至任意位置進行操作。不同於 FileInputStream(僅讀)與 FileOutputStream(僅寫)的單向流設計,RandomAccessFile 實作了 DataInput 與 DataOutput 介面,提供豐富的基本型別讀寫方法。
| 模式 | 說明 | 同步策略 |
|---|---|---|
| "r" | 唯讀模式,嘗試寫入會拋出 IOException | — |
| "rw" | 讀寫模式,標準操作 | 關閉檔案時同步內容至儲存裝置 |
| "rws" | 讀寫 + 內容與中繼資料即時同步 | 每次內容或中繼資料更新皆同步寫入底層儲存 |
| "rwd" | 讀寫 + 僅內容即時同步 | 每次內容更新同步寫入,中繼資料不強制同步 |
所謂「中繼資料」包含檔案大小、建立時間、修改時間、擁有者、權限等資訊。"rws" 強制同步中繼資料,確保檔案系統結構立即持久化;"rwd" 僅同步檔案內容,效能略優於 "rws";"rw" 則依賴作業系統快取策略,關閉時才保證落盤。
// 建構子
RandomAccessFile(File file, String mode)
RandomAccessFile(String fileName, String mode)
// 定位與長度
void seek(long offset) // 移動檔案指標
long getFilePointer() // 取得目前指標位置
long length() // 取得檔案長度
void setLength(long newLength) // 設定檔案長度(可截斷或擴充)
// 基本型別讀取
int read() / read(byte[] b) / read(byte[] b, int off, int len)
final boolean readBoolean()
final byte readByte()
final char readChar()
final double readDouble()
final float readFloat()
final int readInt()
final long readLong()
final short readShort()
final String readUTF()
// 基本型別寫入
void write(int b) / write(byte[] b) / write(byte[] b, int off, int len)
final void writeBoolean(boolean v)
final void writeByte(int v)
final void writeChar(int v)
final void writeDouble(double v)
final void writeFloat(float v)
final void writeInt(int v)
final void writeLong(long v)
final void writeShort(int v)
final void writeUTF(String str)
// 通道操作
final FileChannel getChannel() // 取得 FileChannel,支援 NIO 操作
import java.io.IOException;
import java.io.RandomAccessFile;
import java.nio.charset.StandardCharsets;
public class RandomAccessFileDemo {
private static final String FILE_PATH = "random_access_demo.txt";
public static void main(String[] args) {
try {
demoBasicReadWrite();
demoRandomAccess();
demoFileChannel();
} catch (IOException e) {
e.printStackTrace();
}
}
// 基本讀寫:寫入字串、基本型別,再讀回驗證
private static void demoBasicReadWrite() throws IOException {
try (RandomAccessFile raf = new RandomAccessFile(FILE_PATH, "rw")) {
// 寫入 UTF-8 字串(含長度前綴)
raf.writeUTF("Hello RandomAccessFile");
raf.writeInt(2024);
raf.writeDouble(Math.PI);
raf.writeBoolean(true);
// 重置指標讀取
raf.seek(0);
System.out.println("字串: " + raf.readUTF());
System.out.println("整數: " + raf.readInt());
System.out.println("浮點: " + raf.readDouble());
System.out.println("布林: " + raf.readBoolean());
}
}
// 隨機存取:修改檔案中間資料、截斷、擴充
private static void demoRandomAccess() throws IOException {
try (RandomAccessFile raf = new RandomAccessFile(FILE_PATH, "rw")) {
long originalLen = raf.length();
System.out.println("原始長度: " + originalLen);
// 移至中間覆寫 4 位元組
raf.seek(originalLen / 2);
raf.writeInt(0xCAFEBABE);
// 擴充檔案至 1KB,新增區域填 0
raf.setLength(1024);
System.out.println("擴充後長度: " + raf.length());
// 截斷至 100 位元組
raf.setLength(100);
System.out.println("截斷後長度: " + raf.length());
}
}
// 搭配 FileChannel 進行高效 NIO 操作
private static void demoFileChannel() throws IOException {
try (RandomAccessFile raf = new RandomAccessFile(FILE_PATH, "rw")) {
var channel = raf.getChannel();
var buffer = java.nio.ByteBuffer.allocate(64);
buffer.put("NIO Channel Write".getBytes(StandardCharsets.UTF_8));
buffer.flip();
channel.write(buffer);
System.out.println("Channel 寫入完成,檔案大小: " + channel.size());
}
}
}
RandomAccessFile 適合需頻繁跳躍位置的場景(如資料庫索引、日誌分析),避免全檔讀入記憶體。"rwd" 平衡效能與持久化保證;金融交易等強一致性需求可用 "rws"。getChannel() 結合 MappedByteBuffer 可實現記憶體映射檔案,進一步提升大檔案處理效能。writeUTF/readUTF 使用修改版 UTF-8(含長度前綴),跨平台交互時需注意相容性;一般文字建議自行指定 StandardCharsets.UTF_8。RandomAccessFile 實例需自行同步。seek() 允許定位至檔案末尾之後,後續寫入會隱性擴充檔案(中間補 0),讀取則回傳 -1。finally 區塊確保 close() 被呼叫,釋放檔案鎖定。掌握 RandomAccessFile 的隨機存取與同步機制,能為 Java 檔案處理帶來靈活且高效的解決方案,特別適用於結構化資料儲存與大檔案隨機訪問場景。