前言
本文写的粗糙,仅作于工作间隙的随笔。
传统的Java IO是基于阻塞的,他的工作状态就是“读/写,等待,读/写,等待······”。
缓冲流有字节和字符两种,原理上几乎差不读,本处以字节缓冲路来进行讨论。
一、缓冲输入流
BufferedInputStream extends FileInputStream,缓冲流的设计思想是基于装饰器设计模式的,需要在构造缓冲流的时候传入一个节点流。
缓冲输入流为什么能够提高效率?
简单一句话就是空间换时间。read方法虽然是一个字节一个字节的返回数据,但是他实际上是一次就读取了buf个字节,然后从buf中返回给read方法,如果取光了,在read一次,如此往复。也就是说,采用了缓冲技术之后,缓冲流调用本地IO的次数变为file.length/buf.length,默认buf是8192个字节,因此read方法的性能提高了约8192倍。当然这不是不需要花费代价的,花费的代价就是多消耗了8191个内存字节。
read(arr[])最终也是使用了read(arr[], int, int)方法,此处两者合在一起介绍。
采用了缓冲技术的read(arr)方法,如果arr.length>=buf.length,那么将不会在使用buf,而是直接将磁盘上的数据填充到arr,这样才能保证最好的性能,但是可能引入的风险是arr的大小没有控制好,导致内存紧张;如果arr.length<buf.length,那么还是依旧读满整个buf,然后从buf中将数据System.arrayCopy到arr中,没有了再次读取磁盘到buf,如此重复,实际上最终和磁盘交互的并不是BufferedInputStream,而是通过构造器注入的其他节点流的native
read(arr[])来实现,代码较多,而且CSDN图片抽风,就不再I贴出来了,自行观赏源码吧!
二、缓冲输出流
BufferedOutputStream extends FileOutputStream。
read(int)方法的思想还是空间换时间,使用缓冲技术,则每次都是写buf,直到buf写满了才会把数据刷到磁盘(刷盘的过程是调用构造方法中传入的节点流的write(arr[])来实现的,而不是直接调用native write(int)实现),没有使用缓冲技术,那么每个字节都需要消耗本地的IO资源,写一个字节,使用一次IO资源,然后再阻塞再写,如此重复。
wirte(arr[])最终调用write(arr[], int, int),思想是将arr中的数据刷到磁盘。使用了缓冲流技术,如果arr.length>=buf.length,则直接将arr中的数据刷盘;如果arr.length<buf.length,则将数据写入buf,直到buf写满了才会刷盘,刷盘的过程也是调用构造方法中传入的节点流的write(arr[], int, int)完成。
三、总结
缓冲流之所以能够提高性能,主要是利用了在内存中开辟的buf空间来实现的,减少了直接消耗系统IO资源的次数,从而提高了性能。