前言: 项目实际编写中,使用到了多种文件拷贝方式,有包括专门使用c写了拷贝工具,供给Java调用,也有使用标准的输入输出流,这里分享的是借助 FileChannel 来读写,nio中传送数据使用channel+buffer,大的数据可以使用allocateDirect申请直接内存传输以提高效率。使用示例和注意事项如下:
核心代码如下:
public Boolean channelCopy(String sourcePath, String destPath) {
Boolean result = false;
FileChannel sourceChannel = null;
FileChannel destChannel = null;
try {
sourceChannel = new RandomAccessFile(sourcePath, "r").getChannel(); // 使用RandomeAccessFile实际比InputStream略快,注意读写标识
destChannel = new FileOutputStream(destPath).getChannel();
long size = sourceChannel.size();
for (long left = size; left > 0; ) {
long transferSize = sourceChannel.transferTo((size - left), left, destChannel);
left = left - transferSize;
}
result = true;
} catch (IOException e) {
log.error(e.getMessage(), e);
result = false;
} finally {
try {
if (sourceChannel != null) {
sourceChannel.close();
}
} catch (IOException e) {
log.error(e.getMessage(), e);
}
try {
if (destChannel != null) {
destChannel.close();
}
} catch (IOException e) {
log.error(e.getMessage(), e);
}
}
return result;
}
注意点:
1. channel.transferTo((size - left), left, destChannel) 方法有一个2G(Integer.Max_VALUE 2147483647 )的限制,参照:
使用transferTo方法限制文件传输大小的原因分析_transforto_狗灬的博客
sun.nio.ch.FileChannelImpl#transferTo 中有个限制,也就是Integer.Max_VALUE()
2. 使用 RandomeAccess 而不是 FileInputStream,实测3.49G的文件在win11,32G,12代cpu上,使用FileInputStream ==》 4381ms完成,使用RandomAccessFile ==> 2390ms完成。有一定的效率差的,要注意读写环境的字符集要正确,避免中文乱码,且注意一下new RandomAccessFile(sourcePath, "r")的权限标识,尽量使用r,避免原始文件不存在会创建文件,或者提前判断。
其他参考: fileChannel全解