不同方式复制文件效率的比较

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了不同方式复制文件效率的比较相关的知识,希望对你有一定的参考价值。

文件拷贝

测试复制文件的大小:4.5MB

  1 /*
  2 
  3  * BufferedInputStram&BufferedOutputStream
  4 
  5  * 这两个流类为IO提供了带缓冲区的操作,一般打开文件进行写入
  6 
  7  * 或读取操作时,都会加上缓冲,这种流模式提高了IO的性能
  8 
  9  *
 10 
 11  * 从应用程序中把输入放入文件,相当于将一缸水倒入到另一个
 12 
 13  * 缸中:
 14 
 15  * FileOutPutStream----->write()方法相当于一滴一滴的
 16 
 17  * 把水转移过去
 18 
 19  * DataOutputStream----->writeXxx()方法会方便一些,相当于
 20 
 21  * 一瓢一瓢的把水转移过去
 22 
 23  * BufferedOutputStream---write方法更方便,相当于把水一瓢
 24 
 25  * 一瓢先放入桶中,在从桶中倒入得到缸中
 26 
 27  * */
 28 
 29  
 30 
 31  
 32 
 33 package Zhang;
 34 
 35  
 36 
 37 import java.io.BufferedInputStream;
 38 
 39 import java.io.BufferedOutputStream;
 40 
 41 import java.io.File;
 42 
 43 import java.io.FileInputStream;
 44 
 45 import java.io.FileOutputStream;
 46 
 47 import java.io.IOException;
 48 
 49  
 50 
 51  
 52 
 53 public class IOUtil {
 54 
 55        /**
 56 
 57        * 读取指定的文件内容,按照十六进制输出到控制台
 58 
 59        * 并且每输出10个byte换行
 60 
 61        * @param fileName 文件名
 62 
 63        * @throws FileNotFoundException
 64 
 65        * */
 66 
 67        public static void printHex(String fileName) throws Exception{
 68 
 69               FileInputStream in=new FileInputStream(fileName);
 70 
 71               int b;
 72 
 73               int i=1;//每十个字节换行。
 74 
 75               while((b=in.read())!=-1){
 76 
 77                      if(b<=0xf){
 78 
 79                             //单位十六进制数,前面补0
 80 
 81                             System.out.print("0");
 82 
 83                      }
 84 
 85                      System.out.print(Integer.toHexString(b)+" ");
 86 
 87                      if(i++%10==0){//够十个换行
 88 
 89                             System.out.println();
 90 
 91                      }
 92 
 93               }
 94 
 95               in.close();
 96 
 97        }
 98 
 99        public static void printHexByByteArray(String fileName)throws Exception{
100 
101               FileInputStream in=new FileInputStream(fileName);
102 
103               byte[] buf=new byte[10*1024]; //20KB
104 
105              
106 
107               /*
108 
109               * 从in中批量读取字节,放入到buf这个字节数组中,从0开始放,
110 
111               * 最多放buf.length个,返回的是读取到的字节的个数
112 
113               * */
114 
115               /*
116 
117               int bytes=in.read(buf,0,buf.length);//一次性读完,说明字节数组足够大
118 
119                                                                              //bytes是实际读取到的长度
120 
121               int j=1;                            //j的作用在于接下来的输出中每十个进行一次换行
122 
123               for(int i=0;i<bytes;i++){           //遍历的时候只能到实际读取的位置处,而不是数组的长度
124 
125                      if(buf[i]<=0xf) System.out.print("0");
126 
127                      System.out.print(Integer.toHexString(buf[i])+" ");
128 
129                      if(j++%10==0){
130 
131                             System.out.println();
132 
133                      }
134 
135               }
136 
137               */
138 
139               //当字节数组不够大,一次性读不完文件时我们该怎么办?
140 
141               int bytes=0;
142 
143               int j=1;
144 
145               while((bytes=in.read(buf,0,buf.length))!=-1){
146 
147                      for(int i=0;i<bytes;i++){
148 
149                             //byte类型8位。int类型32位,为了避免类型转换错误,通过&0xff将高24位清零
150 
151                             if(buf[i]<=0xf){
152 
153                                    System.out.print("0");
154 
155                             }
156 
157                             //if(buf[i]<=0xf) System.out.print("0");
158 
159                             System.out.print(Integer.toHexString(buf[i]&0xff)+" ");
160 
161                             if(j++%10==0){
162 
163                                    System.out.println();
164 
165                             }
166 
167                      }
168 
169               }
170 
171               in.close();
172 
173        }
174 
175        /**
176 
177        * 文件的拷贝
178 
179        * */
180 
181        public static void copyFile(File srcFile,File destFile) throws IOException{
182 
183               if(!srcFile.exists()){
184 
185                      throw new IllegalArgumentException(srcFile+"文件不存在");
186 
187               }
188 
189               if(!srcFile.isFile()){
190 
191                      throw new IllegalArgumentException(srcFile+"不是一个文件");
192 
193               }
194 
195               FileInputStream in=new FileInputStream(srcFile);
196 
197               FileOutputStream out=new FileOutputStream(destFile);
198 
199               byte[] buf=new byte[8*1024];
200 
201               int b;
202 
203               while((b=in.read(buf,0,buf.length))!=-1){
204 
205                      //out.write(buf, 0, buf.length);
206 
207                      /*
208 
209                      * 该是写入buf.length个字节还是写入b个字节
210 
211                      * 写buf.length个字节一定是不恰当的,因为最终读取的时候
212 
213                      * buf总会出现一次未被写满的情况出现,这样copy的文件明显
214 
215                      * 不符合要求
216 
217                      *
218 
219                      * 在断点调试中发现即使读取的内容已经到文件的末尾没有把buf
220 
221                      * 数组读满read方法返回的仍是读取到的长度(也就是b)的值
222 
223                      * 在下次循环的时候会返回-1,也就是说 会用b来控制下次write
224 
225                      * 方法写入到数组中的长度才是符合要求的
226 
227                      *
228 
229                      * 说明文档中对read方法的返回值的描述:
230 
231                      * 读入缓冲区的字节总数,如果因为已经到达文件末尾而没有
232 
233                      * 更多的数据,则返回 -1。
234 
235                      *
236 
237                      * 请注意:这里说的是如果因为已经到达文件末尾而没有更多的
238 
239                      * 数据,也就是指当执行read方法的时候是先判断是不是到文件尾,
240 
241                      * 如果是到文件尾才返回-1,如果不是返回读取的字节数。而不
242 
243                      * 是指执行read中执行着时遇到文件尾返回-1.仔细体会一下。
244 
245                      * */
246 
247                      out.write(buf,0,b);
248 
249                     
250 
251                      out.flush();
252 
253                      /*
254 
255                      * 刷新此输出流并强制写出所有缓冲的输出字节。flush 的常规协定是:
256 
257                      * 如果此输出流的实现已经缓冲了以前写入的任何字节,则调用此方法指
258 
259                      * 示应将这些字节立即写入它们预期的目标。
260 
261                      *
262 
263                      * 如果此流的预期目标是由基础操作系统提供的一个抽象(如一个文件),
264 
265                      * 则刷新此流只能保证将以前写入到流的字节传递给操作系统进行写入,
266 
267                      * 但不保证能将这些字节实际写入到物理设备(如磁盘驱动器)。
268 
269                      * */
270 
271               }
272 
273               in.close();
274 
275               out.close();
276 
277        }
278 
279        /**
280 
281        * 进行文件的拷贝,利用带缓冲的字节流
282 
283        * */
284 
285        public static void copyFileByBuffer(File srcFile,File destFile)throws IOException{
286 
287               if(!srcFile.exists()){
288 
289                      throw new IllegalArgumentException(srcFile+"文件不存在");
290 
291               }
292 
293               if(!srcFile.isFile()){
294 
295                      throw new IllegalArgumentException(srcFile+"不是一个文件");
296 
297               }
298 
299              
300 
301               BufferedInputStream bis=new BufferedInputStream(
302 
303                             new FileInputStream(srcFile));
304 
305               BufferedOutputStream bos=new BufferedOutputStream(
306 
307                             new FileOutputStream(destFile));
308 
309               int c;
310 
311               while((c=bis.read())!=-1){
312 
313                      bos.write(c);
314 
315                      bos.flush();//刷新缓冲区
316 
317               }
318 
319               bis.close();
320 
321               bos.close();      
322 
323        }
324 
325        public static void copyByByte(File srcFile,File destFile)throws IOException{
326 
327               if(!srcFile.exists()){
328 
329                      throw new IllegalArgumentException(srcFile+"文件不存在");
330 
331               }
332 
333               if(!srcFile.isFile()){
334 
335                      throw new IllegalArgumentException(srcFile+"不是一个文件");
336 
337               }
338 
339               FileInputStream in=new FileInputStream(srcFile);
340 
341               FileOutputStream out=new FileOutputStream(destFile);
342 
343               int b;
344 
345               while((b=in.read())!=-1){
346 
347                      out.write(b);
348 
349                      out.flush();//不是缓冲的话不写flush也是没有问题的。
350 
351               }
352 
353               in.close();
354 
355               out.close();
356 
357        }      
358 
359 }

 

测试

 

 1 package Zhang;
 2 
 3  
 4 
 5 import java.io.File;
 6 
 7 import java.io.IOException;
 8 
 9  
10 
11  
12 
13  
14 
15 public class IOUtilTest4 {
16 
17        public static void main(String[] args) {
18 
19               try {
20 
21                      long start=System.currentTimeMillis();
22 
23                      IOUtil.copyByByte(new File("/home/zhang/Desktop/1.mp3"), new File("/home/zhang/Desktop/2.mp3"));
24 
25                      long end=System.currentTimeMillis();
26 
27                      System.out.println("一个字节一个字节复制完成,用时:"+(end-start));
28 
29               } catch (IOException e) {
30 
31                      // TODO Auto-generated catch block
32 
33                      e.printStackTrace();
34 
35               }
36 
37               try {
38 
39                      long start=System.currentTimeMillis();
40 
41                      IOUtil.copyFileByBuffer(new File("/home/zhang/Desktop/1.mp3"), new File("/home/zhang/Desktop/3.mp3"));
42 
43                      long end=System.currentTimeMillis();
44 
45                      System.out.println("缓冲复制完成,用时:"+(end-start));
46 
47               } catch (IOException e) {
48 
49                      // TODO Auto-generated catch block
50 
51                      e.printStackTrace();
52 
53               }
54 
55               try {
56 
57                      long start=System.currentTimeMillis();
58 
59                      IOUtil.copyFile(new File("/home/zhang/Desktop/1.mp3"), new File("/home/zhang/Desktop/4.mp3"));
60 
61                      long end=System.currentTimeMillis();
62 
63                      System.out.println("批量复制完成,用时:"+(end-start));
64 
65               } catch (IOException e) {
66 
67                      // TODO Auto-generated catch block
68 
69                      e.printStackTrace();
70 
71               }      
72 
73        }
74 
75 }

 

 

 

输出

一个字节一个字节复制完成,用时:15598

缓冲复制完成,用时:13096

批量复制完成,用时:8

以上是关于不同方式复制文件效率的比较的主要内容,如果未能解决你的问题,请参考以下文章

java多种文件复制方式以及效率比较

eclipse html 打开方式

VsCode 代码片段-提升研发效率

在 Android 中的两个 Fragment 之间传递数据都有哪些不同的方式? [复制]

GoLang几种读文件方式的比较

内联函数和宏比较