1. 通过字节流实现文件的拷贝
/*** 通过字节流实现文件的拷贝
*@paramsourcePath 源文件路径
*@paramtargetPath 目标文件路径*/
public static voidcopyFileByStream(String sourcePath,String targetPath){//源文件路径
File source = newFile(sourcePath);//目标文件路径
File target = newFile(targetPath);//如果源文件不存在则不能拷贝
if(!source.exists()){return;
}//如果目标文件目录不存在则创建
if(!target.getParentFile().exists()){
target.getParentFile().mkdirs();
}try{//实现文件的拷贝
InputStream inputStream = newFileInputStream(source);
OutputStream outputStream= newFileOutputStream(target);int temp = 0;//每次读取1024个字节
byte[] data = new byte[1024];//将每次读取的数据保存到字节数组里面,并且返回读取的个数
while ((temp = inputStream.read(data)) != -1){//输出数组
outputStream.write(data,0,temp);
}
inputStream.close();
outputStream.close();
}catch(IOException e) {
e.printStackTrace();
}
}
View Code
2. 通过字符流实现文件拷贝(使用字符流只能拷贝文本文件)
/*** 通过字符流实现文件的拷贝
*
*@paramsourcePath 源文件路径
*@paramtargetPath 目标文件路径*/
public static voidcopyFileByReaderAndWriter(String sourcePath, String targetPath) {//源文件路径
File source = newFile(sourcePath);//目标文件路径
File target = newFile(targetPath);//如果源文件不存在则不能拷贝
if (!source.exists()) {return;
}//如果目标文件目录不存在则创建
if (!target.getParentFile().exists()) {
target.getParentFile().mkdirs();
}
FileReader in= null;
FileWriter out= null;try{//字符输入流和字符输出流
in = newFileReader(source);
out= newFileWriter(target);char[] c = new char[1024];int temp = 0;//每次读取1024个字符
while ((temp = in.read(c)) != -1) {//输出到文件
out.write(c, 0, temp);
}
}catch(IOException e) {
e.printStackTrace();
}finally{//关闭流
try{if (in != null) {
in.close();
}if (out != null) {
out.close();
}
}catch(IOException e) {
e.printStackTrace();
}
}
}
View Code
3. 通过字节缓冲流实现文件拷贝
/*** 通过字节缓冲流实现文件的拷贝
*
*@paramsourcePath 源文件路径
*@paramtargetPath 目标文件路径*/
public static voidcopyFileByBuffered(String sourcePath, String targetPath){//源文件路径
File source = newFile(sourcePath);//目标文件路径
File target = newFile(targetPath);//如果源文件不存在则不能拷贝
if (!source.exists()) {return;
}//如果目标文件目录不存在则创建
if (!target.getParentFile().exists()) {
target.getParentFile().mkdirs();
}
InputStream in= null;
OutputStream out= null;try{//字节缓冲输入流和字节缓冲输出流
in = new BufferedInputStream(newFileInputStream(source));
out= new BufferedOutputStream(newFileOutputStream(target));byte[] b = new byte[1024];int temp = 0;//每次读取一个1024的字节数组
while((temp = in.read(b)) != -1){//输出到文件
out.write(b,0,temp);
}
}catch(Exception e) {
e.printStackTrace();
}finally{//关闭流
try{if (in != null) {
in.close();
}if (out != null) {
out.close();
}
}catch(IOException e) {
e.printStackTrace();
}
}
}
View Code
4. 通过字符缓冲流拷贝文件(字符缓冲流只能读取文本文件)
/*** 通过字符缓冲流实现文件的拷贝
*
*@paramsourcePath 源文件路径
*@paramtargetPath 目标文件路径*/
public static voidcopyFileByBufferedChar(String sourcePath, String targetPath){//源文件路径
File source = newFile(sourcePath);//目标文件路径
File target = newFile(targetPath);//如果源文件不存在则不能拷贝
if (!source.exists()) {return;
}//如果目标文件目录不存在则创建
if (!target.getParentFile().exists()) {
target.getParentFile().mkdirs();
}
BufferedReader in= null;
BufferedWriter out= null;try{//字符缓冲输入流和字符缓冲输出流
in = new BufferedReader(newFileReader(source));
out= new BufferedWriter(newFileWriter(target));//读取文件(每次读取一行)
String temp = null;while((temp = in.readLine()) != null){//输出到文件
out.write(temp);
}
}catch(Exception e) {
e.printStackTrace();
}finally{//关闭流
try{if (in != null) {
in.close();
}if (out != null) {
out.close();
}
}catch(IOException e) {
e.printStackTrace();
}
}
}
View Code
5. 通过JAVA NIO 非直接缓冲区拷贝文件
/*** 通过JAVA NIO 非直接缓冲区拷贝文件
*
*@paramsourcePath 源文件路径
*@paramtargetPath 目标文件路径*/
public static voidcopyFileByChannel(String sourcePath, String targetPath) {
FileChannel outChannel= null;
FileChannel inChannel= null;
FileInputStream fis= null;
FileOutputStream fos= null;try{
fis= newFileInputStream(sourcePath);
fos= newFileOutputStream(targetPath);//获取通道
inChannel =fis.getChannel();
outChannel=fos.getChannel();//分配指定大小的缓冲区
ByteBuffer buf = ByteBuffer.allocate(1024);while (inChannel.read(buf) != -1) {//转换为读取数据模式
buf.flip();//写入到磁盘
outChannel.write(buf);//清空缓冲区
buf.clear();
}
}catch(Exception e) {
e.printStackTrace();
}finally{//关闭流
try{if (outChannel != null) {
outChannel.close();
}if (inChannel != null) {
inChannel.close();
}if (fis != null) {
fis.close();
}if (fos != null) {
fos.close();
}
}catch(IOException e) {
e.printStackTrace();
}
}
}
View Code
6. 通过JAVA NIO 直接缓冲区拷贝文件
/*** 通过JAVA NIO 直接缓冲区拷贝文件(内存映射文件)
*
*@paramsourcePath 源文件路径
*@paramtargetPath 目标文件路径*/
public static voidcopyFileByChannelBufferd(String sourcePath, String targetPath) {
FileChannel inChannel= null;
FileChannel outChannel= null;try{//获取通道,StandardOpenOption.READ表示可读,StandardOpenOption.WRITE表示可写,StandardOpenOption.CREATE表示可以创建
inChannel =FileChannel.open(Paths.get(sourcePath), StandardOpenOption.READ);
outChannel=FileChannel.open(Paths.get(targetPath), StandardOpenOption.WRITE, StandardOpenOption.READ, StandardOpenOption.CREATE);//创建内存映射文件
MappedByteBuffer inMapped = inChannel.map(FileChannel.MapMode.READ_ONLY, 0, inChannel.size());
MappedByteBuffer outMapped= outChannel.map(FileChannel.MapMode.READ_WRITE, 0, inChannel.size());//直接操作内存映射文件
byte[] buf = new byte[inMapped.limit()];
inMapped.get(buf);
outMapped.put(buf);
}catch(IOException e) {
e.printStackTrace();
}finally{//关闭流
try{if (outChannel != null) {
outChannel.close();
}if (inChannel != null) {
inChannel.close();
}
}catch(IOException e) {
e.printStackTrace();
}
}
}
View Code
7. 通过JAVA NIO 通道传输拷贝文件
方式一:
/*** 通过JAVA NIO 通道传输拷贝文件
*
*@paramsourcePath 源文件路径
*@paramtargetPath 目标文件路径*/
public static voidcopyFileByChannelTransfer(String sourcePath, String targetPath) {
FileChannel inChannel= null;
FileChannel outChannel= null;try{//获取通道
inChannel =FileChannel.open(Paths.get(sourcePath), StandardOpenOption.READ);
outChannel=FileChannel.open(Paths.get(targetPath),StandardOpenOption.WRITE,StandardOpenOption.READ,StandardOpenOption.CREATE);
inChannel.transferTo(0,inChannel.size(),outChannel);
}catch(IOException e) {
e.printStackTrace();
}finally{//关闭流
try{if (outChannel != null) {
outChannel.close();
}if (inChannel != null) {
inChannel.close();
}
}catch(IOException e) {
e.printStackTrace();
}
}
}
View Code
方式二:
/*** 通过JAVA NIO 通道传输拷贝文件
*
*@paramsourcePath 源文件路径
*@paramtargetPath 目标文件路径*/
public static voidcopyFileByChannelTransfer2(String sourcePath, String targetPath) {
FileInputStream fis= null;
FileOutputStream fos= null;
FileChannel inChannel= null;
FileChannel outChannel= null;try{
fis= newFileInputStream(sourcePath);
fos= newFileOutputStream(targetPath);//获取通道
inChannel =fis.getChannel();
outChannel=fos.getChannel();
inChannel.transferTo(0,inChannel.size(),outChannel);
}catch(IOException e) {
e.printStackTrace();
}finally{//关闭流
try{if (outChannel != null) {
outChannel.close();
}if (inChannel != null) {
inChannel.close();
}
}catch(IOException e) {
e.printStackTrace();
}
}
}
View Code
使用示例:
String source = "e:\\demo\\纵天神帝.txt";
String target= "e:\\demo\\";long time1 =System.currentTimeMillis();
copyFileByStream(source, target+ "1.txt");
System.out.println("通过字节流实现文件的拷贝耗时:" + (System.currentTimeMillis() -time1));long time2 =System.currentTimeMillis();
copyFileByReaderAndWriter(source, target+ "2.txt");
System.out.println("通过字符流实现文件的拷贝耗时:" + (System.currentTimeMillis() -time2));long time3 =System.currentTimeMillis();
copyFileByBuffered(source, target+ "3.txt");
System.out.println("通过字节缓冲流实现文件的拷贝耗时:" + (System.currentTimeMillis() -time3));long time4 =System.currentTimeMillis();
copyFileByBufferedChar(source, target+ "4.txt");
System.out.println("通过字符缓冲流实现文件的拷贝耗时:" + (System.currentTimeMillis() -time4));long time5 =System.currentTimeMillis();
copyFileByChannel(source, target+ "5.txt");
System.out.println("通过JAVA NIO通道(非直接缓冲区)实现文件的拷贝耗时:" + (System.currentTimeMillis() -time5));long time6 =System.currentTimeMillis();
copyFileByChannelBufferd(source, target+ "6.txt");
System.out.println("通过JAVA NIO通道(直接缓冲区)实现文件的拷贝耗时:" + (System.currentTimeMillis() -time6));long time7 =System.currentTimeMillis();
copyFileByChannelTransfer(source, target+ "7.txt");
System.out.println("通过JAVA NIO通道传输实现文件的拷贝耗时:" + (System.currentTimeMillis() -time7));long time8 =System.currentTimeMillis();
copyFileByChannelTransfer(source, target+ "8.txt");
System.out.println("通过JAVA NIO通道传输2实现文件的拷贝耗时:" + (System.currentTimeMillis() - time8));
View Code
通过测试发现,使用JAVA NIO通道传输、JAVA NIO通道直接缓冲区以及字节缓冲流拷贝文件效率最高
在java中,FileChannel类中有一些优化方法可以提高传输的效率,其中transferTo( )和 transferFrom( )方法允许将一个通道交叉连接到另一个通道,而不需要通过一个缓冲区来传递数据。只有FileChannel类有这两个方法,因此 channel-to-channel 传输中通道之一必须是 FileChannel。不能在sock通道之间传输数据,不过socket 通道实现WritableByteChannel 和 ReadableByteChannel 接口,因此文件的内容可以用 transferTo( )方法传输给一个 socket 通道,或者也可以用 transferFrom( )方法将数据从一个 socket 通道直接读取到一个文件中。
Channel-to-channel 传输是可以极其快速的,特别是在底层操作系统提供本地支持的时候。某些操作系统可以不必通过用户空间传递数据而进行直接的数据传输。对于大量的数据传输,这会是一个巨大的帮助。
注意:如果要拷贝的文件大于4G,则不能直接用Channel-to-channel 的方法,替代的方法是使用ByteBuffer,先从原文件通道读取到ByteBuffer,再将ByteBuffer写到目标文件通道中。
下面为实现大文件快速拷贝的代码:
packagecom.newflows.notify.test;importjava.io.File;importjava.io.IOException;importjava.io.RandomAccessFile;importjava.nio.channels.FileChannel;public classBigFileCopy {/*** 通过channel到channel直接传输
*@paramsource
*@paramdest
*@throwsIOException*/
public static void copyByChannelToChannel(String source, String dest) throwsIOException {
File source_tmp_file= newFile(source);if (!source_tmp_file.exists()) {return;
}
RandomAccessFile source_file= new RandomAccessFile(source_tmp_file, "r");
FileChannel source_channel=source_file.getChannel();
File dest_tmp_file= newFile(dest);if (!dest_tmp_file.isFile()) {if (!dest_tmp_file.createNewFile()) {
source_channel.close();
source_file.close();return;
}
}
RandomAccessFile dest_file= new RandomAccessFile(dest_tmp_file, "rw");
FileChannel dest_channel=dest_file.getChannel();long left_size =source_channel.size();long position = 0;while (left_size > 0) {long write_size =source_channel.transferTo(position, left_size, dest_channel);
position+=write_size;
left_size-=write_size;
}
source_channel.close();
source_file.close();
dest_channel.close();
dest_file.close();
}public static voidmain(String[] args) {try{long start_time =System.currentTimeMillis();
BigFileCopy.copyByChannelToChannel("E:\\BaiduNetdiskDownload\\PowerDesigner安装包.rar", "E:\\BaiduNetdiskDownload\\dest_file.rar");long end_time =System.currentTimeMillis();
System.out.println("copy time = " + (end_time -start_time));
}catch(IOException e) {
e.printStackTrace();
}
}
}
View Code