黑马程序员技术交流社区

标题: 使用BufferedReader和BufferedWriter做文件复制,速度为何变慢了? [打印本页]

作者: Seven`    时间: 2014-9-14 18:21
标题: 使用BufferedReader和BufferedWriter做文件复制,速度为何变慢了?
  1.                 FileReader fr = null;
  2.                 FileWriter fw = null;
  3.                 BufferedReader br = null;
  4.                 BufferedWriter bw = null;
  5.                 try {
  6.                         fr = new FileReader("demo.txt");
  7.                         fw = new FileWriter("CopyDemo.txt");
  8.                         br = new BufferedReader(fr);
  9.                         bw = new BufferedWriter(fw);
  10.                        
  11. /*//                        使用readLine读一行写一行
  12.                         String s = null;
  13.                         while((s = br.readLine())!=null){
  14.                                 bw.write(s, 0, s.length());
  15.                                 bw.newLine();
  16.                                 bw.flush();
  17.                         }*/
  18.                        
  19.                         char[] ch = new char[1024];
  20.                         int x =0;
  21.                         while((x = br.read(ch))!=-1){
  22.                                 bw.write(ch, 0, x);
  23.                                 bw.newLine();
  24.                                 bw.flush();
  25.                         }
复制代码
以上代码是除了异常处理以外的部分,我分别使用了BufferedReader和BufferedWriter的两种方法进行文件复制;
文件复制是成功的,但是复制使用的时间却很高.
使用读一行写一行的方式进行复制的话,需要1000多毫秒(txt文件,20Mb),使用数组缓冲的话大概是400多毫秒;
两种方式都没有使用FileReader和FileWriter直接进行复制用时少
哪位大神给看看,是不是我的代码写的不对?

作者: 马嘉    时间: 2014-9-14 18:43
其实我也在好奇这个问题,buffered缓冲区的作用是将硬盘上的数据,在内存中开辟一片空间,然后在在内存中写入硬盘中,而没有缓冲区,就是读一个字节就写一个,省去了往内存中存储一部分的步骤了吧,我是这么理解的不知道对不对
作者: Seven`    时间: 2014-9-14 18:58
马嘉 发表于 2014-9-14 18:43
其实我也在好奇这个问题,buffered缓冲区的作用是将硬盘上的数据,在内存中开辟一片空间,然后在在内存中写 ...

好像是这样的啊,不过BufferedReader和BufferedWriter出现不就是为了加快字符流读取和写入速度 的吗?难道只是FileReader和FileWriter对于txt文本读写更快吗?
作者: ssy1939    时间: 2014-9-14 19:04
用byte数组,不是char数组
作者: Seven`    时间: 2014-9-14 19:39
ssy1939 发表于 2014-9-14 19:04
用byte数组,不是char数组

数组那个是我用来测试时间,进行对比的,重点是读一行存一行那个,
而且BufferedReader好像没有read(byte[] b)相关的方法吧?
作者: ssy1939    时间: 2014-9-14 21:08
Seven` 发表于 2014-9-14 19:39
数组那个是我用来测试时间,进行对比的,重点是读一行存一行那个,
而且BufferedReader好像没有read(byte ...

bw.writer();
作者: Seven`    时间: 2014-9-14 22:07
不会java 发表于 2014-9-14 21:02
秘诀就是你一行有多少个字.
你把flush去掉, 把你自己的缓冲数组的size调小一点. 不要大于8192. 你再试试。 ...

flush去掉会快一点,但是把size调小反而会慢,调大一点倒是有一点点提速
作者: Seven`    时间: 2014-9-14 22:09
ssy1939 发表于 2014-9-14 21:08
bw.writer();

可以稍微表达的全面一点吗?我有点想不明白你要做哪些操作
作者: MeryStyle    时间: 2014-9-14 23:13
重点是一行一行读是吧。lz的第一句 bw.write(s, 0, s.length());就已经写错了!!!—————readLine返回的就是一行的内容,直接写入就行了啊,不知道为什么还要那样写,你的时间就浪费到这里了。还有我刚试了该过后效率比你现在的提高了差不多10倍,是不用缓冲区效率的五倍之多,,,所以lz试试吧!
作者: Seven`    时间: 2014-9-15 00:45
MeryStyle 发表于 2014-9-14 23:13
重点是一行一行读是吧。lz的第一句 bw.write(s, 0, s.length());就已经写错了!!!—————readLine返回 ...

这个注意到了,我也测试了,但是没有你说的那么明显,4、5倍倒是有,但是修改后还是没有直接使用FileReader和FileWriter速度快,这个是我经过多次测试,数据量由20M一点点提高到90M都是这样的结果
作者: zeus00456    时间: 2014-9-15 03:37
其实很简单,原因有两个
1.读写次数,buffer的读写次数是行数*2,而数组则是 文件长度/数组长度*2,通常行数是多余后者的,读写操作的次数多了,磁头找寻位置的次数也多了,比如耗费时间。如果你能保证你的文件只有一行,估计会更快
2.判断,用readline时,没读取一个字符都要判断是不是等于'\r'、'\n'这两步判断一个字符做一次肯定也会拖慢速度的。
作者: MeryStyle    时间: 2014-9-15 13:33
Seven` 发表于 2014-9-15 00:45
这个注意到了,我也测试了,但是没有你说的那么明显,4、5倍倒是有,但是修改后还是没有直接使用FileRead ...

我也测试了一下,结果还是使用缓冲区的较快啊,,,
作者: Seven`    时间: 2014-9-15 20:33
MeryStyle 发表于 2014-9-15 13:33
我也测试了一下,结果还是使用缓冲区的较快啊,,,
  1. FileReader reader = null;
  2.                 FileWriter writer = null;
  3.                 try {
  4.                         reader = new FileReader("d:\\1.txt");
  5.                         writer = new FileWriter("e:\\1.txt");
  6.                         char[] ch = new char[1024];
  7.                         int index = 0;
  8.                         while((index=reader.read(ch))!=-1){
  9.                                 writer.write(ch, 0, index);
  10.                                 writer.flush();
  11.                         }       
  12.                 }
复制代码

这是我用字符流测试的代码,你可以试下,不知道你用的是哪个缓冲区做的测试?
作者: Seven`    时间: 2014-9-15 20:34
MeryStyle 发表于 2014-9-15 13:33
我也测试了一下,结果还是使用缓冲区的较快啊,,,
  1. FileReader reader = null;
  2.                 FileWriter writer = null;
  3.                 try {
  4.                         reader = new FileReader("d:\\1.txt");
  5.                         writer = new FileWriter("e:\\1.txt");
  6.                         char[] ch = new char[1024];
  7.                         int index = 0;
  8.                         while((index=reader.read(ch))!=-1){
  9.                                 writer.write(ch, 0, index);
  10.                                 writer.flush();
  11.                         }       
  12.                 }
复制代码

这是我用字符流测试的代码,你可以试下,不知道你用的是哪个缓冲区做的测试?
作者: MeryStyle    时间: 2014-9-16 14:34
我想问下 lz,第六行代码中的 ch 是什么??它不就是一个最多能缓冲1024个字符的 缓冲区吗?! 这是我所用的缓冲区之一,另一个缓冲区当然是BufferedReader,BufferedWriter了。当你复制的源文件不太大,比如只有几十行甚至几百行代码时,上面两种方法显然都比 你所说的直接使用FileReader和FileWriter 复制文件效率高得多;然而,当复制比较大的文件时,比如楼主说的几十MB的文件,有十几万行的数据,这时,BufferedReader,BufferedWriter的readLine()方法肯定是最慢的,然而,使用数组缓冲区方式复制相比较来说效率是最高的,因为它一次复制1024个的字符,当然还可以更多(这要看你定义的数组的大小了)。。。。。代码附上--->
  1. import java.io.*;

  2. public class BufCopyText {

  3.         public static void main(String[] args) throws IOException {
  4.                 bufCopy();
  5.                 // generalCopy1();
  6.                 // generalCopy2();;

  7.         }

  8.         public static void bufCopy() throws IOException {
  9.                 BufferedReader bufr = null;
  10.                 BufferedWriter bufw = null;
  11.                 try {
  12.                         bufr = new BufferedReader(new FileReader("D:\\MathDemo.java"));

  13.                         bufw = new BufferedWriter(new FileWriter("D:\\CopyOfMathDemo.java"));

  14.                         String line = null;
  15.                         long begin = System.currentTimeMillis();
  16.                         while ((line = bufr.readLine()) != null) {
  17.                                 bufw.write(line);
  18.                                 bufw.newLine();
  19.                                 bufw.flush();
  20.                         }
  21.                         long end = System.currentTimeMillis();
  22.                        
  23.                         System.out.println(end - begin + "毫秒 复制成功!");
  24.                 } catch (IOException e) {
  25.                         throw new RuntimeException("复制出错");
  26.                 } finally {
  27.                         if (bufr != null) {
  28.                                 try {
  29.                                         bufr.close();
  30.                                 } catch (IOException e) {
  31.                                         System.out.println("读取流关闭失败!");
  32.                                 }
  33.                         }
  34.                         if (bufw != null) {
  35.                                 try {
  36.                                         bufw.close();
  37.                                 } catch (IOException e) {
  38.                                         System.out.println("写入流关闭失败!");
  39.                                 }
  40.                         }
  41.                 }

  42.         }

  43.         public static void generalCopy1() throws IOException {
  44.                 FileReader fr = new FileReader("D:\\MathDemo.java");
  45.                 FileWriter fw = new FileWriter("D:\\CopyOfMathDemo.java");

  46.                 int line = 0;
  47.                 long begin = System.currentTimeMillis();
  48.                 while ((line = fr.read()) != -1) {
  49.                         fw.write(line);
  50.                 }
  51.                 long end = System.currentTimeMillis();
  52.                 System.out.println(end - begin + "毫秒 复制成功!");
  53.         }

  54.         public static void generalCopy2() throws IOException {
  55.                 FileReader fr = new FileReader("D:\\MathDemo.java");
  56.                 FileWriter fw = new FileWriter("D:\\CopyOfMathDemo.java");

  57.                 char[] ch = new char[1024];
  58.                 int len = 0;
  59.                 long begin = System.currentTimeMillis();
  60.                 while ((len = fr.read(ch)) != -1) {
  61.                         fw.write(ch, 0, len);
  62.                 }
  63.                 long end = System.currentTimeMillis();
  64.                 System.out.println(end - begin + "毫秒 复制成功!");
  65.         }

  66. }
复制代码

作者: Seven`    时间: 2014-9-16 21:26
MeryStyle 发表于 2014-9-16 14:34
我想问下 lz,第六行代码中的 ch 是什么??它不就是一个最多能缓冲1024个字符的 缓冲区吗?! 这是我所用 ...

这样就清楚了,是我之前理解的不对,忽略了数字缓冲区了;
其实我说的使用FileReader比较快也是说的数组缓冲区,如果直接用read读一个写一个的话当然是很慢的;
谢谢指正




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