做項目過程中遇到要解析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;
}
