黑马程序员技术交流社区

标题: BufferedInputStream到底是如何提高效率的?? [打印本页]

作者: 于世德    时间: 2013-7-31 12:39
标题: BufferedInputStream到底是如何提高效率的??

  1. public class InputStreamTest {
  2.     private static final String FILENAME="E:\\电影\\[高清电影]阿甘正传.1994.美国.中文字幕.1280x720.rmvb";
  3.     public static void main(String[] args) throws IOException {
  4.         long l1 = readByBufferedInputStream();
  5.         long l2 = readByInputStream();
  6.         System.out.println("通过BufferedInputStream读取用时:"+l1+";通过InputStream读取用时:"+l2);
  7.     }

  8.     public static long readByInputStream() throws IOException {
  9.         InputStream in=new FileInputStream(FILENAME);
  10.         byte[] b=new byte[8192];
  11.         int l=0;
  12.         long start=System.currentTimeMillis();
  13.         while(in.read(b,0,8192)!=-1){
  14.         }
  15.         long end=System.currentTimeMillis();
  16.         return end-start;
  17.     }

  18.     public static long readByBufferedInputStream() throws IOException {
  19.         BufferedInputStream in=new BufferedInputStream(new FileInputStream(FILENAME));
  20.         byte[] b=new byte[8192];
  21.         int l=0;
  22.         long start=System.currentTimeMillis();
  23.         while(in.read(b,0,8192)!=-1){
  24.         }
  25.         long end=System.currentTimeMillis();
  26.         return end-start;
  27.     }
  28. }
复制代码
以上代码,一共有两个方法,第一个就是用InputStream读取数据的,第二个就是用BufferedInputStream读取数据的,其他的代码都一样,至于缓冲数组大小为8192是因为BufferedInputStream里面的默认数组大小就是8192的。我那个文件大小是1.46G。

但是运行结果很令我诧异:
通过BufferedInputStream读取用时:705;通过InputStream读取用时:669
通过BufferedInputStream读取用时:727;通过InputStream读取用时:690
通过BufferedInputStream读取用时:721;通过InputStream读取用时:689


但是结果BufferedInputStream用时高于InputStream。虽然差的不多,但是在我映像中,BufferedInputStream应该明显小于InputStream的啊。
这个是为什么呢?BufferedInputStream的缓冲功能又是在什么时候用的呢?

作者: longlangcx    时间: 2013-7-31 16:00
说下我的理解,不一定对,毕竟底层的东西不是很了解~

你两个方法都是连续读操作,不涉及写操作,在硬盘都是在一个位置顺序读取,读取新数据覆盖内存中buf里的旧数据,不涉及在实际读、写操作中的硬盘的磁头移位,所以不管你是一个字节一个字节的读,还是8192字节的读,实质上都是连续的读,没什么区别。而你的Buffered流中本身有缓存,你又设置了一个缓存,在指令上面更复杂,所以速度慢些也正常。

举个例子:
有两间教室,一间教室上黑板上面有100个字,另一间教室上黑板上没字。现在让你把那100个字写到另一个教室的黑板上,你读一个字,就跑去写一个字,然后再读一个字,再去写一个字,这样要来回跑100趟,速度肯定慢。而buffered流的作用就相当于是你先把那100个字中的50个记到脑子里,然后再去另一个教室把这50个字写上去,这样跑2趟就完成了,省下来98趟的来回折腾的时间,速度肯定快。

而你这个没有来回跑得过程,就相当于在那里读那100个字,读一个之后再读一个,跟读50个再读50个没有区别,因为你读50个也是要一个字一个字的读。
作者: 于世德    时间: 2013-7-31 16:47
longlangcx 发表于 2013-7-31 16:00
说下我的理解,不一定对,毕竟底层的东西不是很了解~

你两个方法都是连续读操作,不涉及写操作,在硬盘都 ...

不是啊,FileInputStream也有一次读多个字节的方法啊read(byte[] buf),这不也是相当于一次记住许多个字吗?
作者: longlangcx    时间: 2013-7-31 17:25
于世德 发表于 2013-7-31 16:47
不是啊,FileInputStream也有一次读多个字节的方法啊read(byte[] buf),这不也是相当于一次记住许多个字吗 ...

FileInputStream是从硬盘上读,BufferedInputStream是从内存中读,BufferedInputStream自动负责从硬盘读数据。
作者: 无气打火机    时间: 2013-7-31 20:12
FileInputStream 里面的read(buffer)方法,直接读取到自己的buffer 里面
这个是读取到一个数组里面,jvm里面创建一个新对象都需要耗费时间的,而且每一次read都要执行I/O操作,比较慢。
BufferedInputStream在你创建对象的时候就已经建立好缓冲区数组拉,一定程度上可以减少java生成新对象消费的时间。另外用buffered好处,可以参考API...

作为另一种输入流,BufferedInputStream 为添加了功能,即缓冲输入和支持 mark 和 reset 方法的能力。创建 BufferedInputStream 时即创建了一个内部缓冲区数组。读取或跳过流中的各字节时,必要时可根据所包含的输入流再次填充该内部缓冲区,一次填充多个字节。mark 操作记录输入流中的某个点,reset 操作导致在从所包含的输入流中获取新的字节前,再次读取自最后一次 mark 操作以来所读取的所有字节。
作者: abian    时间: 2013-8-1 11:32
无气打火机 发表于 2013-7-31 20:12
FileInputStream 里面的read(buffer)方法,直接读取到自己的buffer 里面
这个是读取到一个数组里面,jvm里 ...

分析的不错




欢迎光临 黑马程序员技术交流社区 (http://bbs.itheima.com/) 黑马程序员IT技术论坛 X3.2