黑马程序员技术交流社区

标题: 【求助】拷贝有了这个,要BufferedInputStream何用? [打印本页]

作者: 黄奕豪    时间: 2012-6-1 14:38
标题: 【求助】拷贝有了这个,要BufferedInputStream何用?
本帖最后由 黄奕豪 于 2012-6-1 14:42 编辑

真的发现这两个拷贝方法差别好大,速度相差十几倍(末尾有截图~~),是我不理解BufferedInputStream和BufferedOutputStream的妙用吗?还是这个真的比BufferedInputStream和BufferedOutputStream好?如果是这样,要BufferedInputStream和BufferedOutputStream有何用?
  1. /*
  2.         对比利用装饰类拷贝,和直接利用byte数组拷贝。
  3. */
  4. import java.io.*;
  5. class CopyDemo1
  6. {
  7.         public static void main(String[] args)
  8.         {
  9.                 long i = System.currentTimeMillis();
  10.                 copy1();
  11.                 long e = System.currentTimeMillis();
  12.                 System.out.println("1++++++"+(e-i)+"毫秒");

  13.                 long i1 = System.currentTimeMillis();
  14.                 copy2();
  15.                 long e1 = System.currentTimeMillis();
  16.                 System.out.println("2++++++"+(e1-i1)+"毫秒");
  17.         }
  18.         //方法一,利用自定义的字符串做缓冲区,实现复制
  19.         public static void copy1()
  20.         {
  21.                 FileInputStream fis = null;
  22.                 FileOutputStream fos = null;
  23.                 int cpymax = 1024*4;
  24.                 byte[] byt = new byte[cpymax];
  25.                 try
  26.                 {
  27.                         fis =new FileInputStream("浮夸原1.mp3");
  28.                         fos =new FileOutputStream("浮夸1.mp3");
  29.                         while(fis.read(byt)!=-1)
  30.                         {
  31.                                 fos.write(byt);
  32.                         }
  33.                 }
  34.                 catch (IOException ioe){}
  35.                 finally
  36.                 {
  37.                         try
  38.                         {
  39.                                 if (fis != null)
  40.                                                 fis.close();
  41.                         }
  42.                         catch (IOException ioe){}                        
  43.                         try
  44.                         {
  45.                                 if (fos != null)
  46.                                                 fos.close();
  47.                         }
  48.                         catch (IOException ioe){}                        
  49.                 }
  50.                
  51.         }
  52.         //方法二:利用系统自定义的BufferedInputStream装饰类拷贝。
  53.         public static void copy2()
  54.         {
  55.                 FileInputStream fis = null;
  56.                 FileOutputStream fos = null;
  57.                 BufferedInputStream bufis = null;
  58.                 BufferedOutputStream bufos = null;
  59.                 try
  60.                 {
  61.                         fis =new FileInputStream("浮夸原2.mp3");
  62.                         fos =new FileOutputStream("浮夸2.mp3");
  63.                         bufis = new BufferedInputStream(fis);
  64.                         bufos =new BufferedOutputStream(fos);
  65.                         int num;
  66.                         while((num=bufis.read()) != -1)
  67.                         {
  68.                                 bufos.write(num);
  69.                         }
  70.                 }
  71.                 catch (IOException ioe){}
  72.                 finally
  73.                 {
  74.                         try
  75.                         {
  76.                                 if (bufis != null)
  77.                                                 bufis.close();
  78.                         }
  79.                         catch (IOException ioe){}
  80.                         try
  81.                         {
  82.                                 if (fos != null)
  83.                                                 bufos.close();
  84.                         }
  85.                         catch (IOException ioe){}
  86.                 }
  87.         }
  88. }
  89. /*
  90. //毕老师自定义的BufferedInputStream类,所用的时间跟系统自定义的一样。
  91. class MyBufferedInputStream
  92. {
  93.         private InputStream in;

  94.         private byte[] buf = new byte[1024*4];
  95.                
  96.         private int pos = 0,count = 0;
  97.         
  98.         MyBufferedInputStream(InputStream in)
  99.         {
  100.                 this.in = in;
  101.         }

  102.         //一次读一个字节,从缓冲区(字节数组)获取。
  103.         public int myRead()throws IOException
  104.         {
  105.                 //通过in对象读取硬盘上数据,并存储buf中。
  106.                 if(count==0)
  107.                 {
  108.                         count = in.read(buf);
  109.                         if(count<0)
  110.                                 return -1;
  111.                         pos = 0;
  112.                         byte b = buf[pos];

  113.                         count--;
  114.                         pos++;
  115.                         return b&255;
  116.                 }
  117.                 else if(count>0)
  118.                 {
  119.                         byte b = buf[pos];

  120.                         count--;
  121.                         pos++;
  122.                         return b&0xff;
  123.                 }
  124.                 return -1;

  125.         }
  126.         public void myClose()throws IOException
  127.         {
  128.                 in.close();
  129.         }
  130. }
  131. */
复制代码

未命名.jpg (32.82 KB, 下载次数: 73)

未命名.jpg

作者: 黑马—陈磊    时间: 2012-6-1 15:15
使用一个byte数组来作为数据读入的缓冲区,以文件存取为例,硬盘存取的速度远低于内存中的数据存取速度。为了减少对硬盘的存取,通常从文件中一次读入一定长度的数据,而写入时也是一次写入一定长度的数据,这可以增加文件存取的效率。java.io.BufferedInputStream与java.io.BufferedOutputStream可以为InputStream、OutputStream类的对象增加缓冲区功能。构建BufferedInputStream实例时,需要给定一个InputStream类型的实例,实现BufferedInputStream时,实际上最后是实现InputStream实例。同样地,在构建BufferedOutputStream时,也需要给定一个OutputStream实例,实现BufferedOutputStream时,实际上最后是实现OutputStream实例。BufferedInputStream的数据成员buf是一个位数组,默认为2048字节。当读取数据来源时,例如文件,BufferedInputStream会尽量将buf填满。当使用read()方法时,实际上是先读取buf中的数据,而不是直接对数据来源作读取。当buf中的数据不足时,BufferedInputStream才会再实现给定的InputStream对象的read()方法,从指定的装置中提取数据。
BufferedInputStream和BufferedOutputStream并没有改变InputStream或 OutputStream的行为,读入或写出时的动作还是InputStream和OutputStream负责。BufferedInputStream和BufferedOutputStream只是在操作对应的方法之前,动态地为它们加上一些额外功能(像缓冲区功能)。

作者: 马超    时间: 2012-6-1 16:34
while(fis.read(byt)!=-1)

                        {

                                fos.write(byt);

                        }



int num;

                        while((num=bufis.read()) != -1)

                        {

                                bufos.write(num);

                        }

两次写得是不是不一样啊?
作者: 黄奕豪    时间: 2012-6-1 18:21
黑马—陈磊 发表于 2012-6-1 15:15
使用一个byte数组来作为数据读入的缓冲区,以文件存取为例,硬盘存取的速度远低于内存中的数据存取速度。为 ...

大哥,我问的不是BufferInputStream等的原理,我问的是为什么用BufferedInputStream反而比用数组直接转存的效率会低那么多啊!!其实BufferedStream的底层原理是先取一段,然后再一个一个的存,那我这个是取一段,然后一段整存,这跟BufferedReader读行的原理一样,可是就是想不明白,为什么BufferedInputStream为什么要这样设计而已,效率差死~~~~~~
作者: 2b青年。    时间: 2012-8-5 21:07
我来给你说 :终于查到了

你去看看java api源码 里面的实现,大体说一下:
FileInputStram里面实现了InputStream的read();这个read()定义为native的 ,具体与操作系统硬盘的复制api有关,实现一次硬盘io读一个字节。(这个java管不了),另外重写了read(byte[] b, int off, int len)方法,而这个重写的方法里面调用的是FileInputStream独有的 private native int readBytes(byte b[], int off, int len) 方法,这个方法也是本地的方法。与硬盘io的直接操作有关,应该用c写的,这个和那个read()有根本的区别,就是一次io读b个字节!BufferedInputStream里面继承了FilterInputStream里面的InputStream成员in,就在你构造这个BufferedInputStream对象的时候FileInputStram传进去了,BufferedInputStream的read()调用的自己的fill(),而fill()调用的FilterInputStream的read(byte b[], int off, int len),继而调用传进去的FileInputStram的read(byte b[], int off, int len),也就调用了native int readBytes(byte b[], int off, int len) 方法。 从而实现了缓存。
你也可以看看BufferedInputStream里面的read(byte b[], int off, int len),方法,都是调用的一样的native方法,具体二者为什么会有时差,和缓存大小有关!就是和readByte里传的b的大小有关!仅此而已。什么方法怎么写都会回归到最原始和windows操作系统打交道的微软上,这个c++,我放弃的真不对。
作者: 2b青年。    时间: 2012-8-5 21:40

上图是我运行的 利用修改的代码:
  1. try
  2. {
  3. fis =new FileInputStream("浮夸原2.mp3");
  4. fos =new FileOutputStream("浮夸2.mp3");
  5. bufis = new BufferedInputStream(fis);
  6. bufos =new BufferedOutputStream(fos);
  7. int num;
  8. int cpymax = 1024*4;
  9. byte[] byt = new byte[cpymax];
  10. while((num=bufis.read(byt)) != -1)
  11. {
  12. bufos.write(byt,0,num);
  13. }
  14. }
  15. catch (IOException ioe){}
复制代码

作者: 唐杨老师    时间: 2012-8-21 07:38
我们老师也经常用自定义数组的形式,关键是这两句
while(fis.read(byt)!=-1)                        读一个存一个,后来直接把byt一起写出,所以块
         fos.write(byt);
while((num=bufis.read()) != -1)            读一个存一个,后来再一个一个写,所以慢(效率并不太高),楼上是又将这个自带缓冲区的输出流加了个 自定义数组,
         bufos.write(num);
使用BufferedReader的读行功能,能快很多,你试试




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