BufferedInputStream和InputStream采用字节数组传输的优劣

在学习Java的IO流的时候,肯定会有一些小伙伴和我一样有这样的困惑:InputStream自身就可以用字节数组作为缓存区,再整个BufferedInputStream干嘛呢?

针对上述问题,看了下java6的API(唯一的官方中文版????),然后整理了下,再用代码测试,最后总结下结论。
首先上图
BufferedInputStream和InputStream采用字节数组传输的优劣
从图上就可以看出,BufferedInputStream是InputStream的子类,其实从设计模式上来说,BufferedInputStream采用装饰器模式,增强了InputStream。

那它是不是就比InputStream自身性能更强呢?

其实不然。如果把整个输入输出看做一次事件,如拷贝某个图片,这涉及到输入流到内存,从内存再到输出流,如果采用InputStream和OutputStream共用一个字节数组作为缓冲区,避免了BufferedInputStream和BufferedOutputStream的字节数组的存取,效率反而更高!

BufferedInputStream和InputStream采用字节数组传输的优劣

我们考虑到应用场景,选取copy这个方式来测试。
分别用图片(1.62M)、压缩文件(388M)和ISO镜像文件(3.87G)

代码:

  1. BufferedInputStream
public class Demo03Test {
    public static void main(String[] args) throws IOException {
        long s = System.currentTimeMillis();
        BufferedInputStream bis = new BufferedInputStream(new FileInputStream("d:\\cn_windows_10_enterprise_x64_dvd_6846957.iso"));
        BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("e:\\cn_windows_10_enterprise_x64_dvd_6846957.iso"));
        byte[] bytes = new byte[1024*8];
        int len=0;
        while((len=bis.read(bytes))!=-1){
            bos.write(bytes,0,len);
        }
        bos.close();
        bis.close();
        long e = System.currentTimeMillis();
        System.out.println("耗时:"+(e-s)+"ms");//25ms  8465ms  132320ms
    }
}

InputStream的子类FileInutStream

public class Demo01CopyFiles {
    public static void main(String[] args) throws IOException {
        long s = System.currentTimeMillis();
        FileInputStream fis = new FileInputStream("d:\\cn_windows_10_enterprise_x64_dvd_6846957.iso");
        FileOutputStream fos = new FileOutputStream("f:\\cn_windows_10_enterprise_x64_dvd_6846957.iso");
        byte[] bytes = new byte[1024*8];
        int len=0;
        while((len=fis.read(bytes))!=-1){
            fos.write(bytes,0,len);
        }
        fos.close();
        fis.close();
        long e = System.currentTimeMillis();
        System.out.println("复制耗时:"+(e-s)+"ms");//37ms  1150ms 130360ms
    }
}
  • 总结
    就如图中所示的,少了中间的转换过程,在大文件传输时,InputStream反而更有优势。

  • 后记
    更加底层的东西就不太懂了,为了查询这些,也搜集了相关的资料,可能和我的阶段性结论相左,也可以私信,大家探讨。
    StackOverFlow的一篇回答,挺精彩的。
    其关键论点A BufferedStream hold a small dynamic portion of another stream. ByteArrayInputStream was covered in 2.,没有太懂,他说Oracle的jdk的tutorial有,链接见下https://docs.oracle.com/javase/tutorial/essential/io/,希望过两年能深入底层,把这些搞懂。