JAVA之NIO按行讀取大檔案
做專案過程中遇到要解析100多M的TXT檔案,併入庫。用之前的FileInputStream、BufferedReader顯然不行了,雖然readLine這方法可以直接按行讀取,但是去讀一個140M左右,68W條資料的檔案時,不但耗時長而且會記憶體溢位,即你等不到讀完68W條資料時就記憶體溢位了。所以得用NIO下面的相關物件及方法。
用到 位元組緩衝區(java.nio.ByteBuffer);用於讀取、寫入、對映和操作檔案的通道( java.nio.channels.FileChannel);設定文字字條集(java.nio.charset.Charset);支援對隨機存取檔案的讀取和寫入(java.io.RandomAccessFile)。
具體思路是:設定兩個緩衝區,一大一小,大的緩衝區為每次讀取的量,小的緩衝區存放每行的資料(確保大小可存放文字中最長的那行)。讀取的時候判斷是不是換行符13,是的話則返回一行資料,不是的話繼續讀取,直到讀完檔案。
實現方法:
FileChannel fc=raf.getChannel();
//一次讀取檔案,讀取的位元組快取數
ByteBuffer fbb=ByteBuffer.allocate(1024*5);
fc.read(fbb);
fbb.flip();
//每行快取的位元組 根據你的實際需求
ByteBuffer bb=ByteBuffer.allocate(500);
//判斷是否讀完檔案
public boolean hasNext() throws IOException {
if(EOF)return false;
if(fbb.position()==fbb.limit()){//判斷當前位置是否到了緩衝區的限制
if(readByte()==0) return false;
}
while(true){
if(fbb.position()==fbb.limit()){
if(readByte()==0) break;
}
byte a=fbb.get();
if(a==13){
if(fbb.position()==fbb.limit()){
if(readByte()==0) break;
}
return true;
}else{
if (bb.position() < bb.limit()) {
bb.put(a);
}else {
if(readByte()==0) break;
}
}
}
return true;
}private int readByte() throws IOException{
//使緩衝區做好了重新讀取已包含的資料的準備:它使限制保持不變,並將位置設定為零。
fbb.rewind();
//使緩衝區做好了新序列通道讀取或相對 get 操作的準備:它將限制設定為當前位置,然後將該位置設定為零。
fbb.clear();
if(this.fc.read(fbb)==-1){
EOF=true;
return 0;
}else{
fbb.flip();
return fbb.position();
}
}
public byte[] next(){
bb.flip();//此處很重要,返回byte陣列方便,行被分割的情況下合併,否則如果正好達到緩衝區的限制時,一箇中文漢字被拆了兩個位元組,就會顯示不正常
byte tm[] = Arrays.copyOfRange(bb.array(), bb.position(), bb.limit());
bb.clear();
return tm;
}