java IO 流操作

来源:互联网 发布:origin最新版软件 编辑:程序博客网 时间:2024/04/28 10:25

因为最近项目有关于大本文读取和指定行读取,读取第多少行到多少行记录,所以就从网上查询一些资料和自己的一些代码总结。
这里通过一个图简单介绍下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.txt2016-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.txt2016-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.txt2016-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.txt2016-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 0
原创粉丝点击