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

  • 相关阅读:
    文本内容超长显示省略号,鼠标移上自动显示全部内容(适用于EasyUI DataGrid)
    Spring注入静态变量的方法,以及CXF如何获取客户端IP
    Agile PLM 表结构说明
    session_start() failed: .......No space left on device问题解决
    如何配置sublime xdebug进行远程调试
    宝塔面板for linux
    Ubuntu 16.04下ssh启用root登录
    mysql- Can't connect to local MySQL server through socket '/var/run/mysqld/mysqld.sock'
    表单重复提交、大并发库存超卖?面试官提出了一个老生常谈的问题,让我陷入了沉思...
    ubuntu16.04 wordpress建站教程
  • 原文地址:https://www.cnblogs.com/firstdream/p/5536002.html
Copyright © 2020-2023  润新知