Java NIO 中的 FileChannel 提供了強大的內存映射文件功能,通過 MappedByteBuffer 可將文件直接映射到內存,實現高效的文件讀寫、共享內存及進程間通信。本文深入解析三種映射模式、文件鎖、分散/聚集 I/O 及零拷貝傳輸。
RandomAccessFile、FileInputStream 或 FileOutputStream 的 getChannel() 方法獲取。| 模式 | 常量 | 特性 | 適用場景 |
|---|---|---|---|
| 只讀 | READ_ONLY | 嘗試修改拋出 ReadOnlyBufferException | 只需讀取大文件,如配置加載、日志分析 |
| 讀寫 | READ_WRITE | 修改直接同步到底層文件,進程可見 | 需要持久化修改,如數據庫索引、緩存文件 |
| 私有/寫時拷貝 | PRIVATE | 修改產生私有副本,不影響原文件,進程隔離 | 臨時處理、模擬修改、父子進程共享內存頁 |
public static void MappedPrivateChannel() throws Exception {
File tempFile = File.createTempFile("mmaptest", null);
RandomAccessFile file = new RandomAccessFile(tempFile, "rw");
FileChannel channel = file.getChannel();
// 初始寫入數據
ByteBuffer temp = ByteBuffer.allocate(100);
temp.put("This is the file content".getBytes());
temp.flip();
channel.write(temp, 0);
temp.clear();
temp.put("This is more file content".getBytes());
temp.flip();
channel.write(temp, 8192); // 跨頁寫入
// 創建三種映射
MappedByteBuffer ro = channel.map(FileChannel.MapMode.READ_ONLY, 0, channel.size());
MappedByteBuffer rw = channel.map(FileChannel.MapMode.READ_WRITE, 0, channel.size());
MappedByteBuffer cow = channel.map(FileChannel.MapMode.PRIVATE, 0, channel.size());
// 修改 COW 緩衝區
cow.position(8);
cow.put("COW".getBytes());
// 修改 R/W 緩衝區
rw.position(9);
rw.put(" R/W ".getBytes());
rw.force(); // 強制刷新到磁盤
// 通過通道寫入
temp.clear();
temp.put("Channel write ".getBytes());
temp.flip();
channel.write(temp, 0);
// 觀察三個緩衝區內容變化
showBuffers(ro, rw, cow);
// ... 後續更多操作演示
}
使用 ByteBuffer[] 數組實現單次調用讀寫多個緩衝區,適合處理消息頭/體分離的協議:
ByteBuffer[] buffers = {head, body};
while (fileChannel.read(buffers) != -1) { /* 讀取 */ }
head.flip(); body.flip();
// 處理數據
while (bfileChannel.write(buffers) > 0) { /* 寫入 */ }
// 共享鎖(讀鎖) FileLock fileLock = fc.tryLock(0, length, true); // 獨占鎖(寫鎖) fileLock = fcb.tryLock(0, length, false);
注意:文件鎖是進程級的,同一 JVM 內多線程間不可重入,需自行協調。
// 零拷貝複製 ac.transferTo(position, count, bc);
transferTo 或 MappedByteBuffer。READ_WRITE 映射。READ_ONLY 映射。PRIVATE 映射。finally 塊中關閉 Channel、RandomAccessFile 並刪除臨時文件。