java IO 流操作

因为最近项目有关于大本文读取和指定行读取,读取第多少行到多少行记录,所以就从网上查询一些资料和自己的一些代码总结。
这里通过一个图简单介绍下java的IO流。
IO流分类

  1. 根据留得数据对象区分:
    高端流:所有内存中的流都属于高端流,比如:InputStreamReader。
    低端流:所有的外界设备中的流都属于低端流,比如InputStream。
  2. 根据数据的流向区分:
    输出流:用来写数据的,由程序(内存)–>>外接设备。
    输入流:用来读取数据的,由外界设备–>>程序(内存)。
    区分:输入流带有Input,输出流带有Output。

  3. 根据流数据的格式区分:
    字节流:处理声音或者图片等二进制的数据的流,比如InputStream 。
    字符流:处理文本数据(如txt文件)的流,比如InputStreamReader。

  4. 根据流数据的包装过程来区分:
    原始流:在实例化流的对象的过程中,不需要另外传入一个流作为自己构造方法的参数的流。
    包装流:在实例化流的对象的过程中,需要传入另外一个流作为自己构造方法参数的流。
    区分:所有的低端流都是原始流,所有的高端流都是包装流。

    IO流对象的继承关系图
    这里写图片描述
    关于更为细致的分类这里略过,下面简单介绍下几个案例。

    读取第100万之后的100条数据。
    方法代码:

    // 按照行号读取文本数据
    public static String readByNum(int lineNumber) throws Exception {

        String str = null;
        FileReader fr = new FileReader(path);
        LineNumberReader lr = new LineNumberReader(fr);
        if (lineNumber < 0 || lineNumber > getTotalLines(new File(path))) {
            log.debug("不在文件的行数范围之内。");
        }
        int i = 1;
        long start = System.currentTimeMillis();
        while((str=lr.readLine())!=null){
            i++;
            if(i>=1000000&&i<1000015){
                log.debug(lr.readLine());
            }
        }
        long end = System.currentTimeMillis();
        fr.close();
        lr.close();

        log.debug("====方法readByNum(int lineNumber)耗时:"+(end-start)+"毫秒");
        return str;
    }

    // 文件内容的总行数。
    public static int getTotalLines(File file) throws IOException {
        FileReader in = new FileReader(file);
        LineNumberReader reader = new LineNumberReader(in);
        String s = reader.readLine();
        int lines = 0;
        while (s != null) {
            lines++;
            s = reader.readLine();
        }
        reader.close();
        in.close();
        return lines;
    }

测试结果如下:因为数据太大,这里测试100w的后10条数据

2016-04-12 21:22:17.321 DEBUG [main][ReadbigTxt.java:53] - 0039892655~许水花
2016-04-12 21:22:17.323 DEBUG [main][ReadbigTxt.java:53] - 0036102712~应金兰
2016-04-12 21:22:17.323 DEBUG [main][ReadbigTxt.java:53] - 0031388582~景德镇市五金交电化工总公司供应站
2016-04-12 21:22:17.324 DEBUG [main][ReadbigTxt.java:53] - 0023055030~胡秀梅
2016-04-12 21:22:17.324 DEBUG [main][ReadbigTxt.java:53] - 0043752004~李吕华
2016-04-12 21:22:17.324 DEBUG [main][ReadbigTxt.java:53] - 0023914932~汪炳荣
2016-04-12 21:22:17.324 DEBUG [main][ReadbigTxt.java:53] - 0024564962~胡香凤
2016-04-12 21:22:17.324 DEBUG [main][ReadbigTxt.java:53] - 0048613725~史三女
2016-04-12 21:22:17.324 DEBUG [main][ReadbigTxt.java:53] - 0043763065~朱永有
2016-04-12 21:22:17.325 DEBUG [main][ReadbigTxt.java:53] - 0053238145~夏松林
2016-04-12 21:22:17.325 DEBUG [main][ReadbigTxt.java:53] - 0040854072~程林娇
2016-04-12 21:22:17.325 DEBUG [main][ReadbigTxt.java:53] - 0029429342~张荣玖
2016-04-12 21:22:17.325 DEBUG [main][ReadbigTxt.java:53] - 0048657929~董昌国
2016-04-12 21:22:17.325 DEBUG [main][ReadbigTxt.java:53] - 0021460884~周忠德
2016-04-12 21:22:17.326 DEBUG [main][ReadbigTxt.java:53] - 0036288939~陈伟涛
2016-04-12 21:22:17.570 DEBUG [main][ReadbigTxt.java:60] - ====方法readByNum(int lineNumber)耗时:256毫秒

如果文本超过200M以上,需要使用缓存,每次读取10M放入缓存,操作之后再次读取。代码如下:

 /**
     * 读取txt文件的内容
     * @param file 想要读取的文件对象
     * 一次读取一行记录
     * 每次读取5m数据放入缓存,读取5000行存入文本,然后继续读取
     * @return 返回文件内容
     * @throws Exception 
     */
    public static String txt2String(File file) throws Exception{
        FileWriter fw = null;
        String path = Utils.getProperty("connectPath2");
        File f = new File(path);
        if (!f.exists()) {
                f.createNewFile();
        }
            //写到文本
        FileOutputStream fos = new FileOutputStream(f); 
        OutputStreamWriter out = new OutputStreamWriter(fos, "UTF-8"); 

        StringBuffer sb = new StringBuffer(); 

        try{
            FileInputStream in = new FileInputStream(file);  
            // 指定读取文件时以UTF-8的格式读取  如果文件超过2G可以改为10M缓存
            BufferedReader br = new BufferedReader(new InputStreamReader(in,"UTF-8"),5*1024*1024); //  用5M的缓冲读取文本文件  
           //BufferedReader br = new BufferedReader(new FileReader(file));//构造一个BufferedReader类来读取文件
            String s = null;
            int count = 0;//计数器
            while((s = br.readLine())!=null){//使用readLine方法,一次读一行
                sb.append(s);
                //sb.append(processConnect(s));//这个方法是我对读取数据的操作,这里略过直接sb.append(s);
                if (count % 5000 == 0) {// 5000条数据写入一次
                    out.write(sb.toString());
                    sb.setLength(0);//清空
                    log.debug("====写入文本成功~");
                }
                count++;
            }



            out.close();
            br.close();
        }catch(Exception e){
            e.printStackTrace();
        }
        return sb.toString();
    }

执行之后一个221M的文本读完并写入到了另一个文本之中。控制台输入如下:

2016-04-12 22:13:56.443 DEBUG [main][ReadTxt2SQL.java:32] - path=F:/OntologyData/tb_data/data.txt
2016-04-12 22:13:58.846 DEBUG [main][ReadTxt2SQL.java:107] - ====写入文本成功~
2016-04-12 22:13:58.846 DEBUG [main][ReadTxt2SQL.java:109] - ====方法txt2String(File file)耗时:2397毫秒
2016-04-12 22:13:58.847 DEBUG [main][ReadTxt2SQL.java:39] - ====整个文本的处理时间:[2455]毫秒

可能有人会对上面代码String path = Utils.getProperty("connectPath2");有疑惑,这其实就是读取文本的路径,我为了方便写了一个通用类,读取配置文件的内容,可以直接改为绝对路径。

可能有人会疑问,为什么我要读取5000条然后存入文本,继续读取然后在存,这样的因为数据量太大,我们内存空间不足会导致内存溢出,所以需要这样做。改为如下:

  while((s = br.readLine())!=null){//使用readLine方法,一次读一行
                sb.append(s);
                //sb.append(processConnect(s));
                /*if (count % 5000 == 0) {// 5000条数据写入一次
                    out.write(sb.toString());//写入文本
                    sb.setLength(0);//清空
                    //log.debug("====写入文本成功~");
                }*/

                count++;
            }
            out.write(sb.toString());//写入文本

控制台打印:

2016-04-12 22:18:58.343 DEBUG [main][ReadTxt2SQL.java:32] - path=F:/OntologyData/tb_data/data.txt
2016-04-12 22:19:03.531 DEBUG [main][ReadTxt2SQL.java:109] - ====写入文本成功~
2016-04-12 22:19:03.531 DEBUG [main][ReadTxt2SQL.java:111] - ====方法txt2String(File file)耗时:4687毫秒
2016-04-12 22:19:03.661 DEBUG [main][ReadTxt2SQL.java:39] - ====整个文本的处理时间:[5411]毫秒

相对于第一种方法,这种效率低一些,现在我把读取内容每行都做处理//sb.append(test(s));

2016-04-12 22:24:53.187 DEBUG [main][ReadTxt2SQL.java:32] - path=F:/OntologyData/tb_data/data.txt
2016-04-12 22:24:56.134 DEBUG [main][ReadTxt2SQL.java:107] - ====写入文本成功~
2016-04-12 22:24:56.135 DEBUG [main][ReadTxt2SQL.java:109] - ====方法txt2String(File file)耗时:2927毫秒
2016-04-12 22:24:56.150 DEBUG [main][ReadTxt2SQL.java:39] - ====整个文本的处理时间:[3014]毫秒

改为一次读完再存

2016-04-12 22:25:54.316 DEBUG [main][ReadTxt2SQL.java:32] - path=F:/OntologyData/tb_data/data.txt
2016-04-12 22:25:57.671 DEBUG [main][ReadTxt2SQL.java:108] - ====写入文本成功~
2016-04-12 22:25:57.672 DEBUG [main][ReadTxt2SQL.java:110] - ====方法txt2String(File file)耗时:3327毫秒
2016-04-12 22:25:57.764 DEBUG [main][ReadTxt2SQL.java:39] - ====整个文本的处理时间:[3499]毫秒

这样看基本时间差距不大,今天先写到这里,等有时间我来测试2G数据,这两种方式的效率。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值