Java实现文件拷贝的4种方法(转)Java实现文件拷贝的4种方法(转)2010-08-05 18:38bysunday,50visits,网摘,收
Java实现文件拷贝的4种方法(转)
Java实现文件拷贝的4种方法(转)
2010-08-05 18:38 by sunday, 50 visits, 网摘, 收藏, 编辑 http://blog.csdn.net/ta8210/archive/2008/01/30/2073817.aspx
使用 java?进行文件拷贝 相信很多人都会用,不过效率上是否最好呢?最近看了看NIO决定试一试 java? NIO 到底有什么性能的提升.
第一种方法:古老的方式
?public?static?long?forJava(File?f1,File?f2)?throws?Exception{
??long?time=new?Date().getTime();
??int?length=2097152;
??FileInputStream?in=new?FileInputStream(f1);
??FileOutputStream?out=new?FileOutputStream(f2);
??byte[]?buffer=new?byte[length];
??while(true){
???int?ins=in.read(buffer);
???if(ins==-1){
????in.close();
????out.flush();
????out.close();
????return?new?Date().getTime()-time;
???}else
????out.write(buffer,0,ins);
??}
?}
方法的2参数分别是原始文件,和拷贝的目的文件.这里不做过多介绍.
实现方法很简单,分别对2个文件构建输入输出流,并且使用一个字节数组作为我们内存的缓存器, 然后使用流从f1 中读出数据到缓存里,在将缓存数据写到f2里面去.这里的缓存是2MB的字节数组
第2种方法:使用NIO中的管道到管道传输
????public?static?long?forTransfer(File?f1,File?f2)?throws?Exception{
????????long?time=new?Date().getTime();
????????int?length=2097152;
????????FileInputStream?in=new?FileInputStream(f1);
????????FileOutputStream?out=new?FileOutputStream(f2);
????????FileChannel?inC=in.getChannel();
????????FileChannel?outC=out.getChannel();
????????int?i=0;
????????while(true){
????????????if(inC.position()==inC.size()){
????????????????inC.close();
????????????????outC.close();
????????????????return?new?Date().getTime()-time;
????????????}
????????????if((inC.size()-inC.position())<20971520)
????????????????length=(int)(inC.size()-inC.position());
????????????else
????????????????length=20971520;
????????????inC.transferTo(inC.position(),length,outC);
????????????inC.position(inC.position()+length);
????????????i++;
????????}
????}
实现方法:在第一种实现方法基础上对输入输出流获得其管道,然后分批次的从f1的管道中像f2的管道中输入数据每次输入的数据最大为2MB
方法3:内存文件景象写(读文件没有使用文件景象,有兴趣的可以回去试试,,我就不试了,估计会更快)
????public?static?long?forImage(File?f1,File?f2)?throws?Exception{
????????long?time=new?Date().getTime();
????????int?length=2097152;
????????FileInputStream?in=new?FileInputStream(f1);
????????RandomAccessFile?out=new?RandomAccessFile(f2,"rw");
????????FileChannel?inC=in.getChannel();
????????MappedByteBuffer?outC=null;
????????MappedByteBuffer?inbuffer=null;
????????byte[]?b=new?byte[length];
????????while(true){
????????????if(inC.position()==inC.size()){
????????????????inC.close();
????????????????outC.force();
????????????????out.close();
????????????????return?new?Date().getTime()-time;
????????????}
????????????if((inC.size()-inC.position())<length){
????????????????length=(int)(inC.size()-inC.position());
????????????}else{
????????????????length=20971520;
????????????}
????????????b=new?byte[length];
????????????inbuffer=inC.map(MapMode.READ_ONLY,inC.position(),length);
????????????inbuffer.load();
????????????inbuffer.get(b);
????????????outC=out.getChannel().map(MapMode.READ_WRITE,inC.position(),length);
????????????inC.position(b.length+inC.position());
????????????outC.put(b);
????????????outC.force();
????????}
????}
实现方法:跟伤2个例子不一样,这里写文件流没有使用管道而是使用内存文件映射(假设文件f2在内存中).在循环中从f1的管道中读取数据到字节数组里,然后在像内存映射的f2文件中写数据.
第4种方法:管道对管道
????public?static?long?forChannel(File?f1,File?f2)?throws?Exception{
????????long?time=new?Date().getTime();
????????int?length=2097152;
????????FileInputStream?in=new?FileInputStream(f1);
????????FileOutputStream?out=new?FileOutputStream(f2);
????????FileChannel?inC=in.getChannel();
????????FileChannel?outC=out.getChannel();
????????ByteBuffer?b=null;
????????while(true){
????????????if(inC.position()==inC.size()){
????????????????inC.close();
????????????????outC.close();
????????????????return?new?Date().getTime()-time;
????????????}
????????????if((inC.size()-inC.position())<length){
????????????????length=(int)(inC.size()-inC.position());
????????????}else
????????????????length=2097152;
????????????b=ByteBuffer.allocateDirect(length);
????????????inC.read(b);
????????????b.flip();
????????????outC.write(b);
????????????outC.force(false);
????????}
????}
这里实现方式与第3种实现方式很类似,不过没有使用内存影射.
?
下面是对49.3MB的文件进行拷贝的测试时间(毫秒)
Start Copy File...? file size:50290KB
CopyFile:b1.rmvb?mode:forChannel??RunTime:3203
CopyFile:b1.rmvb?mode:forImage??RunTime:3328
CopyFile:b1.rmvb?mode:forJava??RunTime:2172
CopyFile:b1.rmvb?mode:forTransfer?RunTime:1406
End Copy File!
解释: 在测试结果中看到 古老方式,和管道向管道传输是最快的,,,,,为什么呢?
我分析是这样的,由于另外2种方法内部都使用了 字节数组作为缓存中转,在加上NIO内部有一个贴近系统的缓存区,这无意就增加了另一个缓存器,所以相对于这2个方法就要慢许多,,如果不使用 字节数组作为数据中转的话相信速度会更快的..
不过比较惊讶的是 管道向管道传输的速度还是真挺吓人,,,