首先还是看一个用3中方式copy文件的测试Demo
分别是:普通Stream文件copy,BuffferedStream进行Copy 和Channel(nio)进行文件Copy的代码和性能测试报告:
1 package com.ctyun.stream; 2 3 import java.io.BufferedInputStream; 4 import java.io.BufferedOutputStream; 5 import java.io.File; 6 import java.io.FileInputStream; 7 import java.io.FileNotFoundException; 8 import java.io.FileOutputStream; 9 import java.io.IOException; 10 import java.nio.channels.FileChannel; 11 /** 12 * 13 * @Description 文件效率copy测试 14 * @author zhanghw@chinatelecom.com.cn 15 * @since 2015年9月11日 16 * @version V1.0 17 */ 18 public class FileCopyEfficientTest { 19 20 //普通io流copy 21 public static void commonCopy(String source, String dest){ 22 FileInputStream in = null; 23 FileOutputStream out = null; 24 try { 25 in = new FileInputStream(new File(source)); 26 out = new FileOutputStream(new File(dest)); 27 28 byte[] b = new byte[2048]; 29 while(in.read(b) != -1 ){ 30 out.write(b); 31 } 32 out.flush(); 33 34 } catch (FileNotFoundException e) { 35 e.printStackTrace(); 36 } catch (IOException e) { 37 // TODO Auto-generated catch block 38 e.printStackTrace(); 39 }finally{ 40 try { 41 if(in != null){ 42 in.close(); 43 } 44 if(out != null){ 45 out.close(); 46 } 47 } catch (IOException e) { 48 // TODO Auto-generated catch block 49 in = null; 50 out =null; 51 e.printStackTrace(); 52 } 53 } 54 } 55 56 //Streambuffer进行copy 57 public static void bufferCopy(String source, String dest){ 58 FileInputStream in = null; 59 FileOutputStream out = null; 60 BufferedInputStream bufferedIn = null; 61 BufferedOutputStream bufferedOut = null; 62 63 try { 64 in = new FileInputStream(new File(source)); 65 out = new FileOutputStream(new File(dest)); 66 67 bufferedIn = new BufferedInputStream(in); 68 bufferedOut = new BufferedOutputStream(out); 69 70 byte[] b = new byte[2048]; 71 while(bufferedIn.read(b) != -1 ){ 72 bufferedOut.write(b); 73 } 74 bufferedOut.flush(); 75 76 } catch (FileNotFoundException e) { 77 e.printStackTrace(); 78 } catch (IOException e) { 79 // TODO Auto-generated catch block 80 e.printStackTrace(); 81 }finally{ 82 try { 83 if(in != null){ 84 in.close(); 85 } 86 if(out != null){ 87 out.close(); 88 } 89 if(bufferedIn != null){ 90 bufferedIn.close(); 91 } 92 if(bufferedOut != null){ 93 bufferedOut.close(); 94 } 95 } catch (IOException e) { 96 // TODO Auto-generated catch block 97 in = null; 98 out =null; 99 bufferedIn = null; 100 bufferedOut = null; 101 e.printStackTrace(); 102 } 103 } 104 } 105 106 //用Channel进行copy 107 public static void channelCopy(String source, String dest){ 108 FileInputStream in = null; 109 FileOutputStream out = null; 110 FileChannel channelIn = null; 111 FileChannel channelOut = null; 112 113 try { 114 in = new FileInputStream(new File(source)); 115 out = new FileOutputStream(new File(dest)); 116 channelIn = in.getChannel(); 117 channelOut = out.getChannel(); 118 119 channelIn.transferTo(0, channelIn.size(), channelOut); 120 121 } catch (FileNotFoundException e) { 122 e.printStackTrace(); 123 } catch (IOException e) { 124 // TODO Auto-generated catch block 125 e.printStackTrace(); 126 }finally{ 127 try { 128 if(in != null){ 129 in.close(); 130 } 131 if(out != null){ 132 out.close(); 133 } 134 if(channelIn != null){ 135 channelIn.close(); 136 } 137 if(channelOut != null){ 138 channelOut.close(); 139 } 140 141 } catch (IOException e) { 142 // TODO Auto-generated catch block 143 in = null; 144 out =null; 145 channelIn = null; 146 channelOut = null; 147 e.printStackTrace(); 148 } 149 } 150 151 } 152 153 //测试因为会线程原因,造成时间不正确 154 /*public static void main(String[] args) { 155 String source = "d:/test.txt"; 156 String dest1 = "d:/temp/test1.txt"; 157 String dest2 = "d:/temp/test2.txt"; 158 String dest3 = "d:/temp/test3.txt"; 159 160 long l1 = System.currentTimeMillis(); 161 commonCopy(source, dest1); 162 long l2 = System.currentTimeMillis(); 163 System.out.println("普通Stream Copy用时:"+(l2-l1)); 164 165 bufferCopy(source, dest2); 166 long l3 = System.currentTimeMillis(); 167 System.out.println("buffer Stream Copy用时:"+(l3-l2)); 168 169 channelCopy(source, dest3); 170 long l4 = System.currentTimeMillis(); 171 System.out.println("channel Stream Copy用时:"+(l4-l3)); 172 173 }*/ 174 175 public static void main(String[] args) { 176 String source = "d:/test.txt"; 177 String dest = "d:/temp/test1.txt"; 178 179 long l1 = System.currentTimeMillis(); 180 // commonCopy(source, dest); 181 bufferCopy(source, dest); 182 // channelCopy(source, dest); 183 long l2 = System.currentTimeMillis(); 184 System.out.println("Copy用时:"+(l2-l1)); 185 186 } 187 188 }
性能测试结果及结论:
测试1:不同文件大小测试时间(在同一main函数中进行测试)
大小 | 普通Copy(毫秒) |
BufferCopy(毫秒)
|
ChannelCopy(毫秒) |
文件类型
|
1m
|
56 |
44
|
72
|
文本
|
128m
|
2095 |
1132
|
437
|
文本
|
512m
|
9215 |
6710
|
10444
|
文本
|
1g
|
19989
|
49358
|
44809
|
文本
|
2g
|
69266
|
63989
|
58310
|
文本
|
结论:通过观察发现此次测试结果之间差异非常大,并且笔者在观察文件copy时,并没有按照正常顺序进行copy,所以(猜测)可能是在同一main方法中因为线程资源不均衡问题,造成测试结果差异较大,不准确(copy文件之间存在干扰)。
为证实以上结论继续如下测试:
测试2:在同一main函数中进行测试
1024M多次测试结果
测试次数
|
大小 | 普通Copy(毫秒) |
BufferCopy(毫秒)
|
ChannelCopy(毫秒) |
文件类型
|
1
|
1g
|
17365 |
34371
|
27906
|
文本
|
2
|
1g
|
39903 |
35203
|
19079
|
文本
|
3
|
1g
|
43865 |
36720
|
28984
|
文本
|
--------------------------------------
结论:每次性能差异很大,原因可能是(猜测):在同一个main方法中由于文件流操作时线程获取cup资源的时间不同造成(copy文件之间存在干扰),
为了保证测试的准确性,修改测试为没法方法在main方法中单独测试。
单独测试,在一个个main方法运行时,保证只有一个copy方法运行(最终测试方案,正确)(copy文件之间相互独立,不存在干扰)
大小 | 普通Copy(毫秒) |
BufferCopy(毫秒)
|
ChannelCopy(毫秒) |
文件类型
|
1m
|
62 |
16
|
31
|
文本
|
128m
|
1953 |
907
|
422
|
文本
|
512m
|
8126 |
3422
|
1141
|
文本
|
1g
|
86944
|
87572
|
17703
|
文本
|
2g
|
66079
|
55298
|
17219
|
文本
|
测试次数
|
大小 | 普通Copy(毫秒) |
BufferCopy(毫秒)
|
ChannelCopy(毫秒) |
文件类型
|
1
|
1g
|
15281 |
8937
|
5860
|
文本
|
2
|
1g
|
15485 |
7203
|
5703
|
文本
|
3
|
1g
|
16068 |
6828
|
5422
|
文本
|
结论:在通常情况下,nio的性能>buffered性能>普通Stream的性能,但是在小文件的时候Buffered性能会比nio好