博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Java实现文件拷贝的4种方法.
阅读量:4600 次
发布时间:2019-06-09

本文共 3589 字,大约阅读时间需要 11 分钟。

使用 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+

转载于:https://www.cnblogs.com/yangkai-cn/p/4016801.html

你可能感兴趣的文章
Perl last和next的用法区别
查看>>
Selenium 管理 Cookies
查看>>
exceptionfunction[LeetCode]Permutations
查看>>
Linux(2)_常用命令2
查看>>
自定义分页
查看>>
[转]DELPHI——调试(1)
查看>>
JS秒数转成分秒时间格式
查看>>
xp_cmdshell 命令的开启与关闭,和状态查询
查看>>
Linux sudoers
查看>>
MySQL详解(18)-----------分页方法总结
查看>>
bzoj 4595 激光发生器
查看>>
multi cookie & read bug
查看>>
js时间转换
查看>>
(转载) Android Studio你不知道的调试技巧
查看>>
POJ2231 Moo Volume 递推 C语言
查看>>
struts2类型转换的具体流程
查看>>
Hdu 1203 I NEED A OFFER!
查看>>
php文件上传类
查看>>
CF219D Choosing Capital for Treeland
查看>>
luogu P3809 【模板】后缀排序
查看>>