总结下文件的快速读取四种方式---小数组+FileInputStream、小数组+BufferedInputStream、BufferedReader字符流按行和小数组+BufferedReader读

目录

一、定义小数组+FileInputStream、小数组+BufferedInputStream、BufferedReader字符流按行和小数组+BufferedReader读取简单说明

二、小数组+FileInputStream读取文件

三、小数组+BufferedInputStream读取文件

四、BufferedReader按行读取文件

五、小数组+BufferedReader读取文件

六、顺提一下拷贝文件


一、定义小数组+FileInputStream、小数组+BufferedInputStream、BufferedReader字符流按行和小数组+BufferedReader读取简单说明

首先,对于相关知识点不是很理解的,推荐花几分钟时间看下我之前写的两篇文章,对这些有个大概了解。

  1. 参考我之前写的一篇文章---字节流介绍
  2. 参考我之前写的一篇文章---字符流介绍

解释一下相关类

相关解释

FileInputStream

输入流,read默认读取一个字节
BufferedInputStream 输入缓冲字节流,一次性可以读取关联文件8*1024个字节
BufferedReader 输入缓冲字符流,一次性可以读取关联文件8*1024个字节
InputStreamReader

字节流转为字符流中间类

byte(char) 这篇文章中指的小数组

经过我的测试得出结论对四种读取效率从高到底排序(质疑的可以下方留言讨论,有更快的读取方式也可以介绍一下):

小数组+FileInputStream > 小数组+BufferedInputStream = 小数组+BufferedReader > BufferedReader按行读取

下面是对四种方式的介绍

1、我认为第一种方式使用小数组+FileInputStream读取方式效率是最高的,就是定义一种byte可以控制的字节流大小进行读取。(注意:是我认为,如果觉得我是错的,可以下方留言

2、第二种方式小数组+BufferedInputStream进行读取,BufferedInputStream中也定义了一个8*1024的byte缓冲区,可以一次性将需要读取的文件8*1024大小的字节流刷到缓冲区中,其实这种读取方式也是一种小数组,只是内部封装了而已。刷到缓冲区后,我们要定义一个byte去缓冲区读取接收它(不定义效率很低),所以它使用的内存是第一种方式的两倍内存,所以我认为自己定义小数组的读取方式效率最高。

3、第三种方式BufferedReader按行读取,内部也定义了8*1024的char缓冲区,通过InputStreamReader转换流将字符流一次性刷到缓冲区中,效率和第二种方式差不了多少,关键是它从缓冲区进行按行读取效率可能会比BufferedInputStream效率要低。一次性读取和每次读取一行,想想也知道哪个效率高了。

4、第四种方式小数组+BufferedReader进行读取,就是在缓冲区中按行读取的情况下改成按char字符小数组读取,当char数组大于一行又或者说一行很少内容的时候,效率肯定比按行读取高。但是内存上也消耗了一个char数组的大小。

总之,第二种方式是对第一种的内部包装,但是读取的时候需要多定义一个数组。第四种方式仅改变了从每次缓冲区读取大小。不管是内存还是速度上,第一种方式都绝对占据优势。

 

二、小数组+FileInputStream读取文件

这是一种个人认为最高效可靠小数组+FileInputStream进行读取方式,下面贴代码。

    @Test
    public void test1() throws IOException {
        //定义可变字符串进行接收
        StringBuffer stringBuffer = new StringBuffer();
        //定义小数组读取(一次读8kb,2m文件大概读取2*1024/8=256次,也就是与磁盘交换256次)
        byte[] bytes = new byte[8*1024];
        //使用FileInputStream输入流
        try(FileInputStream fileInputStream = new FileInputStream("D:\\project_location\\datastructure\\src\\json.json")) {
            long startTime = System.currentTimeMillis();
            int len;
            while ((len = fileInputStream.read(bytes)) != -1) {
                stringBuffer.append(new String(bytes, 0, len));
            }
            System.out.println(i);
            //消耗时间(大概消耗0.16m)
            System.out.println("使用小数组+FileInputStream耗时:"+ (System.currentTimeMillis() - startTime) / 1000.0 + "s");
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

这里采用了8*1024=8k的byte数组形式读取7m多点的文件(读磁盘数为902次,这是我在while里面定义计数器得到的。计算方式也可以:7*1024*1024/8*1024=896次),每次读取7m的文件大概耗时0.16s左右(网络会影响时间长短)。

如果采取1024*1024=1m的byte数组读取则耗时大概是0.13s左右,并且读磁盘数只有8次。虽然byte数组定义越大读取越快,较少磁盘交互次数,但因为消耗了内存,不见得越大越好。

 

三、小数组+BufferedInputStream读取文件

这是第二种方式小数组+BufferedInputStream进行读取读取方式,下面贴代码。

    @Test
    public void test2() throws IOException {
        //定义可变字符串进行接收
        StringBuffer stringBuffer = new StringBuffer();
        //定义小数组读取
        byte[] bytes = new byte[8*1024];
        //使用BufferedInputStream缓冲流
        try(BufferedInputStream is = new BufferedInputStream(new FileInputStream("D:\\project_location\\datastructure\\src\\json.json"));) {
            long startTime = System.currentTimeMillis();
            int len;
            while ((len = is.read(bytes)) != -1) {
                stringBuffer.append(new String(bytes, 0, len));
            }
            //消耗时间(大概消耗0.17s)
            System.out.println("使用小数组+BufferedIuputStream耗时:"+ (System.currentTimeMillis() - startTime) / 1000.0 + "s");
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

因为底层是封装了一个8*1024的缓冲区,关于读磁盘数都和上面第一种方式一样,只是这里多定义了一个外在8*1024的byte去接收字符串,这里耗时大概是0.17s,相比第一种慢了0.01s左右,可能走的封装过程消耗了点时间。其实和第一种效率差不多,除了多消耗一倍内存。

 

四、BufferedReader按行读取文件

这是第三种BufferedReader按行读取方式,下面贴代码。

    @Test
    public void test3() {
        //创建可变字符流接收
        StringBuffer stringBuffer = new StringBuffer();
        //使用BufferedReader流   将字节流转为字符流,进行高效读取
        try(BufferedReader bufferedReader = new BufferedReader(
                new InputStreamReader(new FileInputStream("D:\\project_location\\datastructure\\src\\json.json"),"utf-8"))) {
            String str = null;
            //记录开始时间
            long startTime = System.currentTimeMillis();
            //按行读取
            while ((str = bufferedReader.readLine()) != null) {
                stringBuffer.append(str);
            }
            //花费时间(大概0.26s)
            System.out.println("使用BufferedReader耗时:" + (System.currentTimeMillis() - startTime) / 1000.0  + "s");
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

以上采用了BufferedReader按行进行读取,7m的文件大概用了0.26s左右。

 

五、小数组+BufferedReader读取文件

    @Test
    public void test4() {
        //创建可变字符流接收
        StringBuilder stringBuilder = new StringBuilder();
        //定义小数组读取
        char[] chars = new char[8*1024];
        //使用BufferedReader流   将字节流转为字符流,进行高效读取
        try(BufferedReader bufferedReader = new BufferedReader(
                new InputStreamReader(new FileInputStream("D:\\project_location\\datastructure\\src\\json.json"),"utf-8"))) {
            //记录开始时间
            long startTime = System.currentTimeMillis();
            int len = 0;
            while ((len = bufferedReader.read(chars)) != -1) {
                stringBuilder.append(new String(chars, 0, len));
            }
            //花费时间(大概0.18s)
            System.out.println("使用BufferedReader耗时:" + (System.currentTimeMillis() - startTime) / 1000.0  + "s");
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

以上采用了小数组+BufferedReader进行读取,7m的文件大概用了0.18s左右。

六、顺提一下拷贝文件

拷贝建议用字节流,贴代码

    @Test
    public void test5() {
        byte[] bytes = new byte[8*1024];
        //使用BufferedInputStream输入流
        try (BufferedInputStream bufferedInputStream = new BufferedInputStream(new FileInputStream("D:\\project_location\\datastructure\\src\\json.json"));
        BufferedOutputStream bufferedOutputStream = new BufferedOutputStream(new FileOutputStream("D:\\project_location\\datastructure\\src\\json2.json"))) {
            long startTime = System.currentTimeMillis();
            int len;
            while ((len = bufferedInputStream.read(bytes)) != -1) {
                bufferedOutputStream.write(bytes,0, len);
            }
            //消耗时间(大概消耗0.04s)
            System.out.println("使用BufferedInputStream进行拷贝耗时:" + (System.currentTimeMillis() - startTime) / 1000.0 + "s");
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

消耗时间竟然只有0.04左右...,不定义byte时,用了0.4,十倍差距。

 

 

猜你喜欢

转载自blog.csdn.net/qq_41055045/article/details/107401974