文件复制的过程很简单,从源文件读出数据,再写到目标文件就实现了文件复制,java强大的I/O实现起来很简单,下面是一个文件copy方法:
public static void copy2(String src, String dest) {
int readBufferSize = 4096;
File from_file = new File(src);
File to_file = new File(dest);
FileInputStream from = null; // Stream to read from source
FileOutputStream to = null; // Stream to write to destination
try {
from = new FileInputStream(from_file);
to = new FileOutputStream(to_file);
byte[] buffer = new byte[readBufferSize];
int bytes_read;
while((bytes_read = from.read(buffer)) != -1)
to.write(buffer,0,bytes_read);
}
finally {
if (from != null)
try {
from.close();
}catch(IOException e){
from = null;
e.printStackTrace();
}
if (to != null)
try {
to.close();
} catch (IOException e){
to = null;
e.printStackTrace();
}
}
}
下面改进一下,用带缓冲的输入输出流:
public static void copy2(String src, String dest) {
int readBufferSize = 4096;
File from_file = new File(src);
File to_file = new File(dest);
BufferedInputStream bisFrom = null; // Stream to read from source
BufferedOutputStream bisTo = null; // Stream to write to destination
try {
bisFrom = new BufferedInputStream(new FileInputStream(from_file));
bisTo = new BufferedOutputStream(new FileOutputStream(to_file));
byte[] buffer = new byte[readBufferSize]; // byte buffer
int bytes_read;
while ((bytes_read = bisFrom.read(buffer)) != -1)
bisTo.write(buffer, 0, bytes_read);
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
if (bisFrom != null)
bisFrom.close();
if (bisTo != null)
bisTo.close();
} catch (IOException e) {
bisFrom = null;
bisTo = null;
}
}
}
除了使用java传统的I/O 外,使用nio包里FileChannel类也可以很方便的实现文件复制,下面是一个使用FileChannel的方法:
public static void copyFile(String src, String dest) {
File srcFile = new File(src);
File destFile = new File(dest);
FileChannel sourceChannel = null;
FileChannel destinationChannel = null;
try {
sourceChannel = new FileInputStream(srcFile).getChannel();
destinationChannel = new FileOutputStream(destFile).getChannel();
sourceChannel.transferTo(0, sourceChannel.size(),destinationChannel);
// or
// destinationChannel.transferFrom(sourceChannel,0,sourceChannel.size());
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
if (sourceChannel != null)
sourceChannel.close();
if (destinationChannel != null)
destinationChannel.close();
} catch (IOException e) {
sourceChannel = null;
destinationChannel = null;
}
}
}
使用FileChannel果然简单,一个方法就ok了,那么上面三种方法实现的文件复制速度一样快吗?如果不一样,哪种方式的效率更高一些呢?一般会认为nio具有更高的效率,那FileChannel会不会更快一些呢?实践一下便知。
目标文件选用一个689M大的iso文件,从一个磁盘分区复制到另外一个分区
系统环境: cpu:E2160,内存:单条2G,操作系统:windows xp sp2,JDK1.6.10
测试结果:
方法1 耗时33204毫秒,方法2 耗时23781毫秒,方法3 耗时53859毫秒
实测的结果是FileChannel最慢,而且竟然比文件流读写方式慢了一倍!
是不是一次传输整个文件影响效率呢,看看分段循环传输会不会好一些,把方法3改成下面的形式:
public static void copyFile2(String src, String dest) {
File srcFile = new File(src);
File destFile = new File(dest);
FileChannel sourceChannel = null;
FileChannel destinationChannel = null;
long buffer = 4096;
long byteWritten = 0;
try {
sourceChannel = new FileInputStream(srcFile).getChannel();
destinationChannel = new FileOutputStream(destFile).getChannel();
long filesize = sourceChannel.size();
while (byteWritten < filesize) {
long written = sourceChannel.transferTo(byteWritten, buffer,destinationChannel);
byteWritten += written;
}
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
sourceChannel.close();
destinationChannel.close();
} catch (IOException e) {
sourceChannel = null;
destinationChannel = null;
}
}
}
再做测试,成绩为:31344毫秒 ,果然比一次传输的方式快了不少,速度基本和文件流读写方式持平。
从实际测试结果可以看出,对于比较大的文件,FileChannel循环传输的方式比一次传输速度快,和FileInputStream/FileOutputStream的速度相当,而带缓冲的流读写速度最快。