Java实现文件拷贝的4种方法

Java实现文件拷贝的4种方法.

标签: javaexceptiondatebytebuffernull
  37337人阅读  评论(25)  收藏  举报
  分类:
 

使用 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个方法就要慢许多,,如果不使用 字节数组作为数据中转的话相信速度会更快的..

不过比较惊讶的是 管道向管道传输的速度还是真挺吓人,,, 

我的机器是 IDE硬盘120G 硬盘缓存2MB, 内存1GB, CPU AMD2800+

0
0
 
 
我的同类文章

参考知识库

img
Java EE知识库

img
Java SE知识库

img
Java Web知识库

猜你在找
Java之路
软件测试基础
零基础学Java系列从入门到精通
移动手机APP测试从零开始(初级篇)
EJB核心课程,免费学
Java编程___File各类方法使用实现拷贝特定文件至特定目录下
理解Java NIO
java相关问题
JAVA面试总结
Freemarker 简介 及手册
查看评论
23楼  hety163 2014-01-01 23:07发表 [回复]
为何刚开始lenth初始少了个零,后来又多上了。虽然好像不影响。博主这篇文章很有价值,感谢分享。
22楼  hety163 2014-01-01 22:42发表 [回复]
这顺序没写颠倒吧,倒过来顺序也不一样啊……
21楼  cwj312 2013-07-31 09:44发表 [回复]
我测试过一个大概70M的视频文件,结果差不多,保持在12至13秒之间
20楼  jixuan1989 2013-04-21 15:26发表 [回复]
速度不是一个级别的。。
19楼  jixuan1989 2013-04-21 15:26发表 [回复]
400 M文件测试,第一种最快
18楼  神奇物种 2013-04-06 03:42发表 [回复]
我试了3个文件(按楼主文章的顺序进行测试) ,我觉得哪个快那个慢还得看你是什么文件、文件大小吧,嗯,对于这个问题,有没大神能解释下咧。。。
zip 24.6MB
56
26
521
473

iso 218MB
439
170
3059
3885

iso 1.8GB
58199
75354
138954
130251

rmvb 2.05GB
66023
105136
165375
139661
17楼  Heavan2010 2012-03-09 15:37发表 [回复]
顶。
16楼  Buddhist 2012-03-05 15:41发表 [回复]
[html]  view plain  copy
  1. [/code[code=plain]  
ding
15楼  dafa1893 2012-02-27 10:11发表 [回复]
顶之
14楼  her2006 2011-12-28 12:47发表 [回复]
顶顶更健康哈。感谢分享啊。
13楼  xiangxiang213 2011-08-03 11:31发表 [回复]
顶!
12楼  kinglion114 2011-06-16 09:38发表 [回复]
[e01][e01][e01]
2008年发的帖子,怎么到2010年才有第一条回复??这么好的帖子应该多顶一下!![e03][e03]
11楼  springk 2011-05-26 15:24发表 [回复]
[e01][e01][e01][e01][e01][e03][e03][e03][e03]
10楼  chaofanwei 2011-05-22 23:36发表 [回复]
不错啊,保存起来
9楼  nbda1121440 2011-05-22 22:07发表 [回复]
[e03][e03][e03][e03][e03][e03][e03][e03][e03][e03][e03][e03][e03][e03][e03][e03][e03][e03][e03][e03][e03]
8楼  zzbatluzhou 2011-04-28 12:59发表 [回复]
转一下!
7楼  happy_miyu 2011-04-13 12:23发表 [回复]
我实际测试了几遍,发现管道到管道的方法比传统方法慢十倍左右&#183;&#183;&#183;好奇怪&#183;&#183;&#183;
Re:  iDrinking 2013-02-22 11:58发表 [回复]
回复happy_miyu:我测试也是forChannel慢,forJava快一倍左右,46M的文件...
6楼  zzmmzzzzm 2011-04-03 09:49发表 [回复]
支持一下!!!!!!!!!
5楼  ookk1100ookk 2011-04-02 11:31发表 [回复]
[e02][e01][e01][e01][e01][e01][e01][e01][e01][e01][e01][e01][e01][e01][e01][e01][e01][e01][e01][e01][e01]
谢谢楼主。
4楼  hhlwork 2011-03-28 17:06发表 [回复]
[e01]真不错
3楼  ljl_1120 2011-03-08 15:31发表 [回复]
[e01]
2楼  匿名用户 2010-03-19 11:08发表 [回复]
牛逼不是吹的,管道就是好[e01]
1楼  匿名用户 2010-03-10 17:35发表 [回复]
[e01][e01][e01][e01][e01][e01][e01][e01][e01][e01][e01]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值