問:使用 Java 如何讀取大文件粱玲,你有什么建議或者經驗?
答:我們平常讀取一般文件都是將文件數據直接全部讀取到內存中進行操作的拜轨,這種做法對于小文件是沒有問題的抽减,但對于稍大一些的文件就會拋出 OOM 異常,所以我們應該把大文件分成多個子區(qū)域分多次讀取橄碾。
- 思路一:文件流邊讀邊用胯甩,使用文件流的 read() 方法每次讀取指定長度的數據到內存中,具體樣板代碼如下堪嫂。
//BufferedReader類同
BufferedInputStream reader = new BufferedInputStream(new FileInputStream("big.txt"), 8192);
int bytes = -1;
do {
byte[] tmpArray = new byte[8192];
bytes = reader.read(tmpArray);
if (bytes != -1) {
//做事情
}
} while(bytes > 0);
reader.close();
- 思路二:對大文件建立 NIO (New IO) 的 FileChannel偎箫,每次調用 read() 方法時會先將文件數據讀取到已分配固定長度的
java.nio.ByteBuffer
中,接著從中獲取讀取的數據皆串。這種用 NIO 通道的方法比傳統(tǒng)文件流讀取理論上要快一點淹办,具體樣板代碼如下。
FileInputStream fileIn = new FileInputStream("big.txt");
ByteBuffer byteBuf = ByteBuffer.allocate(65535);
FileChannel fileChannel = fileIn.getChannel();
int bytes = -1;
do {
bytes = fileChannel.read(byteBuf);
if (bytes != -1) {
byte[] array = new byte[bytes];
byteBuf.flip();
byteBuf.get(array);
byteBuf.clear();
//拿array做事情
System.out.println(new String(array));
}
} while (bytes > 0);
byteBuf.clear();
fileChannel.close();
fileIn.close();
- 思路三:內存文件映射恶复,就是把文件內容映射到虛擬內存的一塊區(qū)域中怜森,從而可以直接操作內存當中的數據而無需每次都通過 I/O 去物理硬盤讀取文件,這種方式可以提高速度谤牡,具體樣板代碼如下副硅。
FileInputStream fileIn = new FileInputStream("big.txt");
FileChannel fileChannel = fileIn.getChannel();
MappedByteBuffer mappedBuf = fileChannel.map(FileChannel.MapMode.READ_ONLY, 0, fileChannel.size());
boolean end = false;
do {
int limit = mappedBuf.limit();
int position = mappedBuf.position();
if (position >= limit) {
end = true;
}
int maxSize = 2048;
if (limit - position < maxSize) {
maxSize = limit - position;
}
byte[] array = new byte[maxSize];
mappedBuf.get(array);
//拿array搞事情
System.out.println(new String(array));
} while (!end);
mappedBuf.clear();
fileChannel.close();
fileIn.close();
- 思路四:使用 RandomAccessFile 的 seek() 方法進行分塊讀寫操作,具體實現(xiàn)非常簡單翅萤,和普通文件操作一樣恐疲,不過還是推薦 JDK 1.4 NIO 的內存映射文件。
本文參考自 Java 讀取大文件相關面試題基礎解析