本文對比傳統阻塞 IO、帶緩衝 IO 及 NIO 內存映射三種讀取大文件的方式,附帶完整可運行代碼。
public static void readFile(String path) throws FileNotFoundException {
long start = System.currentTimeMillis();
int bufSize = 1024;
FileChannel fcin = new RandomAccessFile(new File(path), "r").getChannel();
ByteBuffer rBuffer = ByteBuffer.allocate(bufSize);
byte[] bs = new byte[bufSize];
while (fcin.read(rBuffer) != -1) {
int rSize = rBuffer.position();
rBuffer.rewind();
rBuffer.get(bs);
rBuffer.clear();
String temp = new String(bs, 0, rSize);
// 按行處理 temp...
}
System.out.println("傳統IO讀取,總耗時:" + (System.currentTimeMillis() - start) + "ms");
}
public static void readFile1(String path) {
long start = System.currentTimeMillis();
BufferedReader br = new BufferedReader(new FileReader(new File(path)));
String line;
while ((line = br.readLine()) != null) { System.out.println(line); }
br.close();
System.out.println("緩衝字符流讀取,總耗時:" + (System.currentTimeMillis() - start) + "ms");
}
public static void readFile3(String path) {
long start = System.currentTimeMillis();
File file = new File(path);
long fileLength = file.length();
final int BUFFER_SIZE = 0x300000; // 3MB
MappedByteBuffer inputBuffer = new RandomAccessFile(file, "r").getChannel()
.map(FileChannel.MapMode.READ_ONLY, 0, fileLength);
byte[] dst = new byte[BUFFER_SIZE];
for (int offset = 0; offset < fileLength; offset += BUFFER_SIZE) {
int len = Math.min(BUFFER_SIZE, (int)(fileLength - offset));
for (int i = 0; i < len; i++) dst[i] = inputBuffer.get(offset + i);
Scanner scan = new Scanner(new ByteArrayInputStream(dst)).useDelimiter("XXX");
while (scan.hasNext()) System.out.print(scan.next() + "XXX");
scan.close();
}
System.out.println("NIO 內存映射讀取,總耗時:" + (System.currentTimeMillis() - start) + "ms");
}
| 方式 | 特點 | 適用場景 |
|---|---|---|
| 標準 IO + 手動緩衝 | 可控緩衝區大小,底層控制力強 | 特定二進制協議解析 |
| BufferedReader | 代碼簡潔,自動換行處理 | 文本文件逐行讀取 |
| MappedByteBuffer | OS 直接映射文件到內存,減少用戶/內核態拷貝 | 大文件(GB 級)高性能讀寫 |
內容來源:《磁盤 IO 工作機制》微信訂閱號:it_pupil。