1. 程式人生 > >JAVA之NIO按行讀取大檔案

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;
    }