需處理 200MB+ 文本文件,傳統 BufferedReader 逐行讀取較慢,且難以隨機定位。MappedByteBuffer 將文件直接映射到記憶體,由 OS 虛擬記憶體管理分頁載入,適合大文件順序/隨機讀取。
import java.io.*;
import java.nio.*;
import java.nio.channels.*;
public class LargeFileReader {
public static void main(String[] args) throws IOException {
File file = new File("bigdata.txt");
long fileSize = file.length();
try (RandomAccessFile raf = new RandomAccessFile(file, "r");
FileChannel channel = raf.getChannel()) {
// 映射整個文件(或分段映射,單次映射上限 2GB)
MappedByteBuffer buffer = channel.map(FileChannel.MapMode.READ_ONLY, 0, fileSize);
// 1. 順序讀取並解析行
int limit = buffer.limit();
StringBuilder line = new StringBuilder();
for (int i = 0; i < limit; i++) {
byte b = buffer.get(i);
if (b == '\n') {
processLine(line.toString());
line.setLength(0);
} else if (b != '\r') {
line.append((char) b);
}
}
if (line.length() > 0) processLine(line.toString());
// 2. 隨機存取示例:讀取中間 100 字節
buffer.position(limit / 2);
byte[] sample = new byte[100];
buffer.get(sample);
System.out.println("中間片段: " + new String(sample, StandardCharsets.UTF_8));
}
}
private static void processLine(String line) {
// 這裡處理有效數據,如正則提取、入庫等
if (line.contains("ERROR")) System.out.println(line);
}
}
read() 系統調用與用戶/核心態拷貝。buffer.position(offset) 即可跳轉,無需重新開啟流。MappedByteBuffer 無 close(),依賴 GC 回收 DirectByteBuffer 觸發 Cleaner 釋放映射。大量映射建議手動 sun.misc.Cleaner 或升級 JDK 9+ 使用 MemorySegment。final int MAP_SIZE = 512 * 1024 * 1024; // 512MB per segment
for (long offset = 0; offset < fileSize; offset += MAP_SIZE) {
long size = Math.min(MAP_SIZE, fileSize - offset);
MappedByteBuffer buf = channel.map(FileChannel.MapMode.READ_ONLY, offset, size);
// 處理 buf...
// 手動釋放(需反射或 JDK 9+)
((DirectBuffer) buf).cleaner().clean();
}
| 方案 | 優點 | 缺點 | 適用場景 |
|---|---|---|---|
| MappedByteBuffer | 高效、隨機存取 | 映射大小限制、關閉麻煩 | 大文件分析、日誌挖掘、索引建立 |
| BufferedReader | 簡單、流式、低記憶體 | 僅順序、無隨機存取 | 逐行處理、轉換格式 |
| Files.lines (Java 8) | Stream API、並行流 | 全量載入行列表 | 中小文件、函數式處理 |