1.背景

java复制文件的方式其实有很多种,可以分为

传统的字节流读写复制FileInputStream,FileOutputStream,BufferedInputStream,BufferedOutputStream

传统的字符流读写复制FileReader,FileWriter,BufferWriter,BufferedWriter,BufferedReader

NIO系列的FileChannel

FileChannel+缓冲

java.nio.Files.copy()

第三方包中的FileUtils.copy方法,比如org.apache.commons.io.FileUtils,org.codehaus.plexus.util.FileUtils等等.

所以呢,看看各种方法效率怎么样,主要衡量的标准就是时间,另外的一些标准包括大文件的复制时的内存溢出等问题.

2.概述

由于很多时候复制文件都包括了文件夹下的所有子目录及文件的复制,所以作者采用的遍历+复制方法去复制文件.就是把整个复制过程分为先遍历,遍历的过程中遇到文件夹就创建,遇到文件就调用不同的复制方法.

遍历的5种方法:

(1)File.listFiles()

(2)File.list()

(3)org.codehaus.plexus.util.FileUtils.getFiles()

(4)org.apache.commons.io.FileUtils.listFiles()

(5)java nio中的java.nio.file.Files.walkFileTree

复制的8种方法:

(1)FileInputStream+FileOutputStream

(2)BufferedInputStream+BufferedOutputStream

(3)FileReader+FileWriter

(4)BufferedReader+BufferedWriter

(5)FileChannel

(6)FileChannel+buffer

(7)org.apache.commons.io.FileUtils.copyFile()

(8)java.nio.file.Files.copy()

另外作者不太想看控制台.....所以配合了一点swing使用.

3.jar包

4.遍历

(1)listFiles()

private static void traverseByListFiles(File srcFile,File desFile) throws IOException

{

if(srcFile.isDirectory())

{

File[] files = srcFile.listFiles();

assert files != null;

for(File file : files)

{

File desFileOrDir = new File(desFile.getAbsolutePath() + File.separator + file.getName());

if(file.isDirectory())

{

if(desFileOrDir.exists())

desFileOrDir.delete();

desFileOrDir.mkdirs();

}

traverseByListFiles(file, desFileOrDir);

}

}

else

{

copyFile(srcFile, desFile);

}

}

通过srcFile的listFiles()获取所有的子文件与子文件夹,然后判断是否是目录

如果是目录,首先判断有没有这个文件(有时候本来是文件夹但是却存在同名的文件,就先删除),再创建文件夹,然后递归执行函数.

如果不是目录,直接把两个File作为参数进行文件复制,里面用什么方法后面会设置.

(2)list()

private static void traverseByList(File srcFile,File desFile) throws IOException

{

if (srcFile.isDirectory())

{

String[] files = srcFile.list();

assert files != null;

for (String file : files)

{

File subSrcFile = new File(srcFile, file);

File subDesFile = new File(desFile, file);

if (subSrcFile.isDirectory())

{

if (subDesFile.exists())

subDesFile.delete();

subDesFile.mkdirs();

}

traverseByList(subSrcFile, subDesFile);

}

}

else

{

copyFile(srcFile, desFile);

}

}

list与第一种listFiles()类似,不过是String[],也是先判断目录,创建目录,不是目录直接复制

(3)org.codehaus.plexus.util.FileUtils.getFiles

private static void traverseByGetFiles(File srcFile, File desFile) throws IOException

{

if (srcFile.isDirectory())

{

java.util.List fileList = org.codehaus.plexus.util.FileUtils.getFiles(srcFile,null,null);

for (File file : fileList)

{

File desFileOrDir = new File(desFile.getAbsolutePath() + File.separator + file.getName());

if(file.isDirectory())

{

if(desFileOrDir.exists())

desFileOrDir.delete();

desFileOrDir.mkdirs();

}

traverseByListFiles(file, desFileOrDir);

}

}

else

{

copyFile(srcFile, desFile);

}

}

这是用了别人的工具类进行遍历.

org.codehaus.plexus.util.FileUtils.getFiles(srcFile,null,null);

返回的结果的java.util.List

(4)Commons.io工具包

private static void traverseByCommonsIO(File srcFile, File desFile) throws IOException

{

if (srcFile.isDirectory())

{

Collection files = org.apache.commons.io.FileUtils.listFiles(srcFile,null,false);

for (File file : files)

{

File desFileOrDir = new File(desFile.getAbsolutePath() + File.separator + file.getName());

if(file.isDirectory())

{

if(desFileOrDir.exists())

desFileOrDir.delete();

desFileOrDir.mkdirs();

}

traverseByCommonsIO(file, desFileOrDir);

}

}

else

{

copyFile(srcFile, desFile);

}

}

使用org.apache.commons.io.FileUtils的listFiles方法,参数为要遍历的目录,一个null和一个false,第二个参数表示过滤器,表示过滤出特定后缀名的文件,类型为String [],第三个布尔参数表示是否递归访问子目录.

(5)NIO--walkFileTree

利用FileVisitor这个接口.实际中常用SimpleFileVisitor.

private static void traverseByNIO2(File srcFile) throws IOException

{

java.nio.file.Files.walkFileTree(srcFile.toPath(), new SimpleFileVisitor<>() {

@Override

public FileVisitResult visitFile(Path path, BasicFileAttributes attrs) throws IOException

{

File d = new File(des.toString() + path.toAbsolutePath().toString().substring(src.toString().length()));

new File(d.toString().substring(0, d.toString().lastIndexOf(File.separator))).mkdirs();

copyFile(path.toFile(), d);

return FileVisitResult.CONTINUE;

}

});

}

FileVisitor接口定义了四个方法,分别为:

public interface FileVisitor

{

FileVisitResult preVisitDirectory(T dir,BasicFileAttributes attrs)

{

//访问dir前的操作,dir类型一般为java.nio.Path

}

FileVisitResult postVisitDirectory(T dir,BasicFileAttributes attrs)

{

//访问dir后的操作

}

FileVisitResult visitFile(T file,BasicFileAttributes attrs)

{

//访问file时的操作

}

FileVisitResult visitFileFailed(T file,BasicFileAttributes attrs)

{

//访问file失败时的操作

}

}

在上面的例子中只是实现了visitFile,因为只是复制操作,首先判断是否是源目录的路径,不是的话创建文件夹再复制文件.

这里说一下返回值FileVisitResult.FileVisitResult是一个枚举类型,根据返回值判断是否继续遍历.

FileVisitResult可取值:

CONTINUE:继续

TERMINNATE:结束

SKIP_SIBLINGS:继续,跳过同一目录的节点

SKIP_SUBTREE:继续,跳过子目录,但会访问子文件

5.复制

(1)FileInputStream+FileOutputStream

首先是经典的字节流FileInputStream+FileOutputStream,这个比较简单,使用FileInputStream读取后使用FileOutputStream写入,不过效率嘛.....一般般.

private static void copyByFileStream(File srcFile,File desFile) throws IOException

{

FileInputStream inputStream = new FileInputStream(srcFile);

FileOutputStream outputStream = new FileOutputStream(desFile);

byte [] b = new byte[1024];

while(inputStream.read(b) != -1)

{

outputStream.write(b);

addCopySize();

}

inputStream.close();

outputStream.close();

}

这里说一下三个read方法的区别,FileInputStream有三个read方法:

input.read();

input.read(b);

input.read(b,off,len);

A.read()

逐个字节进行读取,返回int,写入时直接使用write(n);

int n = input.read();

output.write(n);

这个可以说是三个read中最慢的....作者试了一个2G左右的文件,用了大概10分钟才复制160M......

B.read(b)

参数是一个byte [],将字节缓冲到其中,返回数组的字节个数,这个比read()快很多.

byte [] b = new byte[1024];

while(input.read(b) != -1)

output.write(b);

C.read(b,off,len)

这个方法其实和read(b)差不多,read(b)相当于省略了参数的read(b,off,len).

byte [] b = new byte[1024];

int n;

while((n = input.read(b,0,1024))!=-1)

output.write(b,0,n);

public int read(byte b[], int off, int len) throws IOException

{

return readBytes(b, off, len);

}

public int read(byte b[]) throws IOException

{

return readBytes(b, 0, b.length);

}

这两个都是调用一样的readBytes():

private native int readBytes(byte b[], int off, int len) throws IOException;

至于效率...可以看看结果(作者用的是10G内的小文件):

可以看到,没有哪个一定比另外一个更快(不过最后一个误差有点太大了?7G不够的文件.).

采用哪一个建议自己去测试,毕竟这存在很多误差,比如文件,java版本,机器本身等等,仅供参考.

(2)BufferedInputStream+BufferedOutputStream

缓冲字节流BufferedInputStream+BufferedOutputStream,相比起FileInputStream,BufferedInputStream读取时会先从缓冲区读取数据,缓冲区无可读数据再从文件读取,所以会比FileInputStream快.

private static void copyByBufferStream(File srcFile,File desFile) throws IOException

{

BufferedInputStream inputStream = new BufferedInputStream(new FileInputStream(srcFile));

BufferedOutputStream outputStream = new BufferedOutputStream(new FileOutputStream(desFile));

byte [] b = new byte[1024];

while(inputStream.read(b) != -1)

{

addCopySize();

outputStream.write(b);

}

inputStream.close();

outputStream.close();

}

这里也说一下BufferedInputStream的三个read(实际上还有,还有readN,与read(),read()肯定最慢,readN作者很少用,所以就没列出来了)

read(b);

read(b,off,len);

readAllBytes();

A.read(b)

这个其实和FileInputStream的那个没啥区别,把一个字节数组仍进去就好了.

B.read(b,off,len)

这个....也和FileInputStream那个没啥区别,不说了

C.readAllBytes()

这个一次可以读取所有的字节.不过用这个虽然省事,可以直接

output.write(input.readAllBytes());

但是呢,有代价的:

会出现OutOfMemory错误,就是对于大文件还是老老实实分开吧,不要"一口搞定","多吃几口".

看看效率:

readAllBytes对于大文件(作者这个是5G内的文件)直接爆内存....

readAllBytes()又爆了.....这个才2G不到的文件...readAllBytes()看来不是很给力啊....不过对于小文件效率还可以接受.

(3)FileReader+FileWriter

字符流读写FileReader+FileWriter,相比起字节流的read,基本上把byte[]换成char[]即可,因为是逐个字符读取,而字节流是逐个字节读取因此采用byte[].

注意这个不能用来读取图片,音乐等文件,不然复制出来的文件打不开.

private static void copyByFileReader(File srcFile,File desFile) throws IOException

{

FileReader reader = new FileReader(srcFile);

FileWriter writer = new FileWriter(desFile);

char [] c = new char[1024];

while(reader.read(c) != -1)

{

addCopySize();

writer.write(c);

}

reader.close();

writer.close();

}

(4)BufferedReader+BufferedWriter

缓冲字符流读写BufferedReader+BufferedWriter,BufferedReader相比起FileReader有一个readLine()方法,可以每行读入,会比FileReader快.对应的BufferedWriter提供了write(String)方法,当然也有write(String s,int off,int len).同样这个不能用来读取图片等.

private static void copyByBufferReader(File srcFile,File desFile) throws IOException

{

BufferedReader reader = new BufferedReader(new FileReader(srcFile));

BufferedWriter writer = new BufferedWriter(new FileWriter(desFile));

char [] c = new char[1024];

while(reader.read(c) != -1)

{

addCopySize();

writer.write(c);

}

reader.close();

writer.close();

}

(5)NIO--FileChannel

通过FileChannel复制,首先通过FileInputStream与FileOutputStream打开流,再用getChannel()方法.最后使用transferTo()或transferFrom()进行复制,一条语句即可,十分方便,而且效率很高.

private static void copyByFileChannel(File srcFile,File desFile) throws IOException

{

FileChannel srcChannel = new FileInputStream(srcFile).getChannel();

FileChannel desChannel = new FileOutputStream(desFile).getChannel();

srcChannel.transferTo(0,srcChannel.size(),desChannel);

srcChannel.close();

desChannel.close();

}

(6)NIO--FileChannel+ByteBuffer

在利用了FileInputStream与FileOutputStream打开了FileChannel的基础上,配合ByteBuffer使用.

private static void copyByFileChannelWithBuffer(File srcFile,File desFile) throws IOException

{

FileChannel srcChannel = new FileInputStream(srcFile).getChannel();

FileChannel desChannel = new FileOutputStream(desFile).getChannel();

ByteBuffer buffer = ByteBuffer.allocateDirect(1024);

while(srcChannel.read(buffer) != -1)

{

buffer.flip();

desChannel.write(buffer);

buffer.clear();

addCopySize();

}

srcChannel.close();

desChannel.close();

}

flip的意思是"翻转",

buffer.flip();

把Buffer从写模式变为读模式,接着write(buffer),再把buffer清空.

看看这两种方法效率:

另外作者发现transferTo的"上限"为2G,就是对于大于2G的单个文件最多最能复制2个G.

所以...对于大文件没有可比性了.

(7)FileUtils.copyFile()

这是工具类,没啥好说的,参数是两个File,分别表示源与目标.

private static void copyByCommonsIO(File srcFile,File desFile) throws IOException

{

FileUtils.copyFile(srcFile, desFile);

}

(8)Files.copy()

这是官方提供的Files工具类,前两个参数为Path,分别表示源与目标,可以设置第三个参数(或者省略),表示选项.例如可以设置

StandardCopyOption.REPLACE_EXISTING

private static void copyByFiles(File srcFile,File desFile) throws IOException

{

Files.copy(srcFile.toPath(), desFile.toPath(), StandardCopyOption.REPLACE_EXISTING);

}

注意Files.copy会保持文件的隐藏属性,原来是隐藏的文件复制后也是隐藏的.以上7种则不会.

6.其他

(1)swing布局

A.网格布局

主JFrame采用了网格布局

setLayout(new GridLayout(3,1,5,3));

三行一列,因为只要三个按钮,选择源文件(夹),选择目标文件夹,选择遍历方式.

选择遍历方式/复制方式的JFrame同样适用了网格布局:

showTraverseMethod.setLayout(new GridLayout(5,1,3,3));

showCopyMethod.setLayout(new GridLayout(4,2,5,5));

B.居中

setBounds(

(int) (Toolkit.getDefaultToolkit().getScreenSize().getWidth() / 2) - 200,

(int) (Toolkit.getDefaultToolkit().getScreenSize().getHeight() / 2) - 200,

400, 400);

高400,宽400,利用ToolKit.getDefaultToolKit().getScreenSize()获取屏幕的高度和宽度实现居中.

C.组件的添加与删除

由于在主JFrame中只有三个按钮,选择完遍历方式后需要更新这个组件,作者的做法是先删除这个组件在添加组件:

traverseMethodButton.setVisible(false);

remove(traverseMethodButton);

add(copyMethodButton);

copyMethodButton.setVisible(true);

设置它不可见再删除,再添加另一组件,再设置可见.

(2)进度条

进度条这个东西把作者搞得很惨啊......其实就是新建一个线程就可以了.

核心代码为:

new Thread(

() ->

{

int percent;

while ((percent = getCopyPercent()) < 100)

{

try

{

Thread.sleep(100);

}

catch(InterruptedException e)

{

e.printStackTrace();

}

copyProgressBar.setValue(percent);

}

}

).start();

作者的JProgressBar是直接添加在一个JFrame中的,不用什么太复杂的布局.

获取百分比后调用setValue(),一定要新建一个线程操作,不然不能正常显示进度条.

另外复制的操作建议使用SwingWorker.

SwingWorker copyTask = new SwingWorker<>()

{

@Override

protected String doInBackground()

{

try

{

if (traverseMethod[0])

traverseByListFiles(src, des);

else if (traverseMethod[1])

traverseByList(src, des);

else if (traverseMethod[2])

traverseByGetFiles(src, des);

else if (traverseMethod[3])

traverseByCommonsIO(src, des);

else if (traverseMethod[4])

traverseByNIO2(src);

else

{

showProgressBar.dispose();

showMessage("遍历失败,找不到遍历方法");

}

}

catch (IOException e)

{

e.printStackTrace();

showProgressBar.dispose();

showMessage("未知错误复制失败");

}

finish(start);

return null;

}

};

copyTask.execute();

7.测试

说了那么多来点实际的.

(以下所有的测试都是删除复制的文件后再进行新一次的复制.)

(1)1G文件

1G file

File.listFiles()

File.list()

plexus.util.FileUtils.getFiles()

commons.io.FileUtils.listFiles

Files.walkFileTree

FileIntput/OutputStream

20.189s

21.152s

18.249s

20.131s

21.782s

BufferedInput/OuputStream

17.761s

23.786s

22.118s

19.646s

16.806s

FileReader/Writer

61.334s

58.3s

58.904s

58.679s

55.762s

BufferedReader/Writer

63.287s

59.546s

56.664s

58.212s

59.884s

FileChannel

20.097s

22.272s

22.751s

22.765s

20.291s

FileChannel+ByteBuffer

18.857s

22.489s

23.148s

22.337s

17.213s

FileUtils.copyFile

25.398s

21.95s

22.808s

25.325s

22.483s

Files.copy

16.272s

14.166s

17.057s

14.987s

10.653s

文件的话其实纵向比较即可,因为基本不用怎么遍历,横向比较可以勉强看作求平均值.

对于非文本文件,FileReader/Writer和BufferedReader/Writer没有太大的参考意义,比如复制视频文件是打不开的,而且复制出来的文件会变大.对于单文件Files.copy的性能非常好,java的nio果然厉害.

(2)10G文件

10G file

File.listFiles()

File.list()

plexus.util.FileUtils.getFiles()

commons.io.FileUtils.listFiles

Files.walkFileTree

FileIntput/OutputStream

171.427s

173.146s

172.611s

184.182s

250.251s

BufferedInput/OuputStream

203.509s

174.792s

167.727s

177.451s

217.53s

FileReader/Writer

187.55s

169.306s

226.571s

168.982s

218.303s

BufferedReader/Writer

155.134s

165.883s

166.192s

176.488s

206.306s

FileChannel

34.48s

35.445s

43.896s

41.827s

41.755s

FileChannel+ByteBuffer

175.632s

167.091s

178.455s

182.977s

183.763s

FileUtils.copyFile

203.997s

206.623s

201.01s

213.949s

208.739s

Files.copy

209.898s

186.889s

244.355s

222.336s

244.68s

这个10G的文件是文本文件.

现在可以看看FileChannel的这一行,明显所花的时间要比其他要少,为什么呢?

因为文件大于2G.FileChannel的trasferTo方法只能写入最多2G的文件,所以对于大于2G的文件复制出来只有2G,因此FileChannel的这一行没有太大可比性.对于文本文件,BufferedReader/Writer的复制速度是最快的了,其次是FileInput/OutputStream.对于单个大文件,apache的FileUtils与NIO的Files.copy的速度比FileInputStream慢啊...

(3)1G目录

1G dir

File.listFiles()

File.list()

plexus.util.FileUtils.getFiles()

commons.io.FileUtils.listFiles

Files.walkFileTree

FileIntput/OutputStream

23.549s

99.386s

143.388s

13.451s

10.773s

BufferedInput/OuputStream

6.306s

59.458s

20.704s

6.668s

6.616s

FileReader/Writer

49.059s

103.257s

51.995s

49.729s

51.509s

BufferedReader/Writer

59.932s

127.359s

51.731s

51.418s

50.317s

FileChannel

40.082s

71.713s

17.617s

15.782s

19.777s

FileChannel+ByteBuffer

33.355s

83.845s

19.68s

10.288s

17.152s

FileUtils.copyFile

24.163s

63.979s

8.277s

6.115s

19.513s

Files.copy

14.528s

28.215s

6.578s

5.883s

7.502s

对于目录的话可以考虑放弃BufferedReader与FileReader了,除非全部是文本文件,否则推荐使用BufferedInput/OutputStream与Files.copy()进行复制,工具类FileUtils的复制方法表现还是不错的,但相比起java标准的Files.copy效率都差了.

对于FileChannel与配合缓冲使用的FileChannel,1G的话好像不相上下.

遍历方式的话...可以看到plexus的遍历方法表现差距很大,而apache的listFiles或者java nio的walkFileTree比较稳定且速度还可以,推荐使用这两种方式遍历目录.

(4)10G目录

10G dir

File.listFiles()

File.list()

plexus.util.FileUtils.getFiles()

commons.io.FileUtils.listFiles

Files.walkFileTree

FileIntput/OutputStream

216.822s

228.792s

227.908s

240.042s

191.863s

BufferedInput/OuputStream

218.599s

210.941s

207.375s

213.991s

167.614s

FileReader/Writer

536.747s

550.755s

550.415s

548.881s

516.684s

BufferedReader/Writer

587.612s

552.55s

549.716s

553.484s

498.18s

FileChannel

115.126s

117.538s

117.456s

118.207s

97.626s

FileChannel+ByteBuffer

225.887s

224.932s

222.077s

223.812s

180.177s

FileUtils.copyFile

233.724s

230.199s

232.133s

223.286s

189.737s

Files.copy

229.819s

227.562s

226.793s

226.78s

181.071s

FileReader与BufferedReader这两行可以忽略了.对于小文件用FileChannel的话还是不错的,对于大文件一定要用FileChannel的话可以配合ByteBuffer使用,不过从数据上看效果比BufferedInput/OutputStream要低.

再看看org.apache.commons.io.FileUtils与java.nio.file.Files的copy,差别不太,效果接近,但在1G的时候差距有点大.

遍历方式的话,java nio的walkFileTrees最快.

当然这些测试仅供参考,具体使用哪一个要看看具体环境,另外这种方式把遍历与复制分开,apache的FileUtils有方法可以直接复制目录的,因此,使用哪个更合适还需要个人具体测试.

8.源码

作者比较偷懒全部仍在一个文件了.七百行.

import java.awt.*;

import javax.swing.*;

import java.nio.*;

import java.nio.channels.*;

import java.io.*;

import java.nio.file.*;

import java.nio.file.attribute.*;

import java.util.*;

import org.apache.commons.io.*;

public class Test extends JFrame

{

public static final long serialVersionUID = 12398129389122L;

private JFrame showTraverseMethod = new JFrame("遍历方式");

private JFrame showCopyMethod = new JFrame("复制方式");

private JButton traverseMethodButton = new JButton("请选择遍历方式");

private JButton copyMethodButton = new JButton("请选择复制方式");

private JButton copyButton = new JButton("开始复制");

private JButton traverseByListFiles = new JButton("File.listFiles()");

private JButton traverseByList = new JButton("File.list()");

private JButton traverseByGetFiles = new JButton("(plexus)getFiles()");

private JButton traverseByCommonsIO = new JButton("Commons IO");

private JButton traverseByNIO2 = new JButton("NIO2");

private JButton copyByFileStream = new JButton("File stream");

private JButton copyByBufferStream = new JButton("Buffer stream");

private JButton copyByFileReader = new JButton("File reader");

private JButton copyByBufferReader = new JButton("Buffer reader");

private JButton copyByFileChannel = new JButton("File channel");

private JButton copyByFileChannelWithBuffer = new JButton("File channel with buffer");

private JButton copyByCommonsIO = new JButton("Commons IO");

private JButton copyByFiles = new JButton("Files.copy");

public Test()

{

JButton src = new JButton("选择源文件(夹)");

src.addActionListener(

event ->

{

JFileChooser fileChooser = new JFileChooser();

fileChooser.setFileSelectionMode(JFileChooser.FILES_AND_DIRECTORIES);

fileChooser.showDialog(new Label(), "选择文件(夹)");

FilesCopy.setSrc(fileChooser.getSelectedFile());

}

);

JButton des = new JButton("选择目标文件夹");

des.addActionListener(

event ->

{

JFileChooser fileChooser = new JFileChooser();

fileChooser.setFileSelectionMode(JFileChooser.FILES_AND_DIRECTORIES);

fileChooser.showDialog(new JLabel(),"选择文件夹");

FilesCopy.setDes(fileChooser.getSelectedFile());

}

);

traverseMethodButton.addActionListener(

event ->

{

traverseByListFiles.addActionListener(

e->

{

FilesCopy.setTraverseByListFiles();

showTraverseMethod.dispose();

}

);

traverseByList.addActionListener(

e ->

{

FilesCopy.setTraverseByList();

showTraverseMethod.dispose();

}

);

traverseByGetFiles.addActionListener(

e ->

{

FilesCopy.setTraverseByGetfiles();

showTraverseMethod.dispose();

}

);

traverseByCommonsIO.addActionListener(

e ->

{

FilesCopy.setTraverseByCommonsIO();

showTraverseMethod.dispose();

}

);

traverseByNIO2.addActionListener(

e ->

{

FilesCopy.setTraverseByNIO2();

showTraverseMethod.dispose();

}

);

showTraverseMethod.setLayout(new GridLayout(5,1,3,3));

showTraverseMethod.setTitle("遍历方式");

showTraverseMethod.setBounds((int) (Toolkit.getDefaultToolkit().getScreenSize().getWidth() / 2) - 200,

(int) (Toolkit.getDefaultToolkit().getScreenSize().getHeight() / 2) - 200, 400, 400);

showTraverseMethod.setVisible(true);

showTraverseMethod.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

showTraverseMethod.add(traverseByListFiles);

showTraverseMethod.add(traverseByList);

showTraverseMethod.add(traverseByGetFiles);

showTraverseMethod.add(traverseByCommonsIO);

showTraverseMethod.add(traverseByNIO2);

traverseMethodButton.setVisible(false);

remove(traverseMethodButton);

add(copyMethodButton);

copyMethodButton.setVisible(true);

}

);

copyMethodButton.addActionListener(

event ->

{

copyByFileStream.addActionListener(

e ->

{

FilesCopy.setCopyByFileStream();

showCopyMethod.dispose();

}

);

copyByBufferStream.addActionListener(

e ->

{

FilesCopy.setCopyByBufferStream();

showCopyMethod.dispose();

}

);

copyByFileReader.addActionListener(

e ->

{

FilesCopy.setCopyByFileReader();

showCopyMethod.dispose();

}

);

copyByBufferReader.addActionListener(

e ->

{

FilesCopy.setCopyByBufferReader();

showCopyMethod.dispose();

}

);

copyByFileChannel.addActionListener(

e ->

{

FilesCopy.setCopyByFileChannel();

showCopyMethod.dispose();

}

);

copyByFileChannelWithBuffer.addActionListener(

e ->

{

FilesCopy.setCopyByFileChannelWithBuffer();

showCopyMethod.dispose();

}

);

copyByCommonsIO.addActionListener(

e ->

{

FilesCopy.setCopyByCommonsIO();

showCopyMethod.dispose();

}

);

copyByFiles.addActionListener(

e ->

{

FilesCopy.setCopyByFiles();

showCopyMethod.dispose();

}

);

showCopyMethod.setLayout(new GridLayout(4,2,5,5));

showCopyMethod.setTitle("复制方式");

showCopyMethod.setBounds(

(int) (Toolkit.getDefaultToolkit().getScreenSize().getWidth() / 2) - 200,

(int) (Toolkit.getDefaultToolkit().getScreenSize().getHeight() / 2) - 200, 400, 400);

showCopyMethod.setVisible(true);

showCopyMethod.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

showCopyMethod.add(copyByFileStream);

showCopyMethod.add(copyByBufferStream);

showCopyMethod.add(copyByFileReader);

showCopyMethod.add(copyByBufferReader);

showCopyMethod.add(copyByFileChannel);

showCopyMethod.add(copyByFileChannelWithBuffer);

showCopyMethod.add(copyByCommonsIO);

showCopyMethod.add(copyByFiles);

copyMethodButton.setVisible(false);

remove(copyMethodButton);

add(copyButton);

copyButton.setVisible(true);

}

);

copyButton.addActionListener(

event ->

{

if(FilesCopy.haveSelectedSrcAndDes())

{

FilesCopy.copy();

copyButton.setVisible(false);

remove(copyButton);

add(traverseMethodButton);

traverseMethodButton.setVisible(true);

}

else

JOptionPane.showMessageDialog(null,"请先选择源文件(夹)与目标文件夹!");

}

);

setLayout(new GridLayout(3,1,5,3));

setTitle("复制文件");

setBounds((int) (Toolkit.getDefaultToolkit().getScreenSize().getWidth() / 2) - 200,

(int) (Toolkit.getDefaultToolkit().getScreenSize().getHeight() / 2) - 200, 400, 400);

setVisible(true);

setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

add(src);

add(des);

add(traverseMethodButton);

}

public static void main(String[] args) {

new Test();

}

}

class FilesCopy

{

private static File src = null;

private static File des = null;

private static long desSize = 0;

private static long srcSize = 0;

private static boolean [] traverseMethod = {false,false,false,false,false,false};

private static boolean[] copyMethod = { false, false, false, false, false, false ,false,false};

private static JFrame showProgressBar = new JFrame();

private static JProgressBar copyProgressBar = new JProgressBar();

private static JTextField textField = new JTextField();

private static int index = 0;

private static int getCopyPercent()

{

return (int)(desSize * 100.0 / srcSize);

}

private static void addCopySize() {

desSize += 1024L;

}

public static void setTraverseByListFiles()

{

traverseMethod[0] = true;

}

private static void traverseByListFiles(File srcFile,File desFile) throws IOException

{

if(srcFile.isDirectory())

{

File[] files = srcFile.listFiles();

assert files != null;

for(File file : files)

{

File desFileOrDir = new File(desFile.getAbsolutePath() + File.separator + file.getName());

if(file.isDirectory())

{

if(desFileOrDir.exists())

desFileOrDir.delete();

desFileOrDir.mkdirs();

}

traverseByListFiles(file, desFileOrDir);

}

}

else {

copyFile(srcFile, desFile);

}

}

public static void setTraverseByList()

{

traverseMethod[1] = true;

}

private static void traverseByList(File srcFile,File desFile) throws IOException

{

if (srcFile.isDirectory())

{

String[] files = srcFile.list();

assert files != null;

for (String file : files)

{

File subSrcFile = new File(srcFile, file);

File subDesFile = new File(desFile, file);

if (subSrcFile.isDirectory())

{

if (subDesFile.exists())

subDesFile.delete();

subDesFile.mkdirs();

}

traverseByList(subSrcFile, subDesFile);

}

}

else

{

copyFile(srcFile, desFile);

}

}

public static void setTraverseByGetfiles()

{

traverseMethod[2] = true;

}

private static void traverseByGetFiles(File srcFile, File desFile) throws IOException

{

if (srcFile.isDirectory())

{

java.util.List fileList = org.codehaus.plexus.util.FileUtils.getFiles(srcFile,null,null);

for (File file : fileList)

{

File desFileOrDir = new File(desFile.getAbsolutePath() + File.separator + file.getName());

if(file.isDirectory())

{

if(desFileOrDir.exists())

desFileOrDir.delete();

desFileOrDir.mkdirs();

}

traverseByListFiles(file, desFileOrDir);

}

}

else

{

copyFile(srcFile, desFile);

}

}

public static void setTraverseByCommonsIO()

{

traverseMethod[3] = true;

}

private static void traverseByCommonsIO(File srcFile, File desFile) throws IOException

{

if (srcFile.isDirectory())

{

Collection files = org.apache.commons.io.FileUtils.listFiles(srcFile,null,false);

for (File file : files)

{

File desFileOrDir = new File(desFile.getAbsolutePath() + File.separator + file.getName());

if(file.isDirectory())

{

if(desFileOrDir.exists())

desFileOrDir.delete();

desFileOrDir.mkdirs();

}

traverseByCommonsIO(file, desFileOrDir);

}

}

else {

copyFile(srcFile, desFile);

}

}

public static void setTraverseByNIO2()

{

traverseMethod[4] = true;

}

private static void traverseByNIO2(File srcFile) throws IOException

{

java.nio.file.Files.walkFileTree(srcFile.toPath(), new SimpleFileVisitor<>() {

@Override

public FileVisitResult visitFile(Path path, BasicFileAttributes attrs) throws IOException {

File d = new File(des.toString() + path.toAbsolutePath().toString().substring(src.toString().length()));

new File(d.toString().substring(0, d.toString().lastIndexOf(File.separator))).mkdirs();

copyFile(path.toFile(), d);

return FileVisitResult.CONTINUE;

}

});

}

public static void setCopyByFileStream()

{

copyMethod[0] = true;

}

private static void copyByFileStream(File srcFile,File desFile) throws IOException

{

FileInputStream inputStream = new FileInputStream(srcFile);

FileOutputStream outputStream = new FileOutputStream(desFile);

byte [] b = new byte[1024];

while(inputStream.read(b) != -1)

{

outputStream.write(b);

addCopySize();

}

inputStream.close();

outputStream.close();

}

public static void setCopyByBufferStream()

{

copyMethod[1] = true;

}

private static void copyByBufferStream(File srcFile,File desFile) throws IOException

{

BufferedInputStream inputStream = new BufferedInputStream(new FileInputStream(srcFile));

BufferedOutputStream outputStream = new BufferedOutputStream(new FileOutputStream(desFile));

byte [] b = new byte[1024];

while(inputStream.read(b) != -1)

{

addCopySize();

outputStream.write(b);

}

inputStream.close();

outputStream.close();

}

public static void setCopyByFileReader()

{

copyMethod[2] = true;

}

private static void copyByFileReader(File srcFile,File desFile) throws IOException

{

FileReader reader = new FileReader(srcFile);

FileWriter writer = new FileWriter(desFile);

char [] c = new char[1024];

while(reader.read(c) != -1)

{

addCopySize();

writer.write(c);

}

reader.close();

writer.close();

}

public static void setCopyByBufferReader()

{

copyMethod[3] = true;

}

private static void copyByBufferReader(File srcFile,File desFile) throws IOException

{

BufferedReader reader = new BufferedReader(new FileReader(srcFile));

BufferedWriter writer = new BufferedWriter(new FileWriter(desFile));

char [] c = new char[1024];

while(reader.read(c) != -1)

{

addCopySize();

writer.write(c);

}

reader.close();

writer.close();

}

public static void setCopyByFileChannel()

{

copyMethod[4] = true;

}

private static void copyByFileChannel(File srcFile,File desFile) throws IOException

{

FileChannel srcChannel = new FileInputStream(srcFile).getChannel();

FileChannel desChannel = new FileOutputStream(desFile).getChannel();

srcChannel.transferTo(0,srcChannel.size(),desChannel);

srcChannel.close();

desChannel.close();

}

public static void setCopyByFileChannelWithBuffer()

{

copyMethod[5] = true;

}

private static void copyByFileChannelWithBuffer(File srcFile,File desFile) throws IOException

{

FileChannel srcChannel = new FileInputStream(srcFile).getChannel();

FileChannel desChannel = new FileOutputStream(desFile).getChannel();

ByteBuffer buffer = ByteBuffer.allocateDirect(1024);

while(srcChannel.read(buffer) != -1)

{

buffer.flip();

desChannel.write(buffer);

buffer.clear();

addCopySize();

}

srcChannel.close();

desChannel.close();

}

public static void setCopyByCommonsIO()

{

copyMethod[6] = true;

}

private static void copyByCommonsIO(File srcFile,File desFile) throws IOException

{

FileUtils.copyFile(srcFile, desFile);

}

public static void setCopyByFiles()

{

copyMethod[7] = true;

}

private static void copyByFiles(File srcFile,File desFile) throws IOException

{

Files.copy(srcFile.toPath(), desFile.toPath(), StandardCopyOption.REPLACE_EXISTING);

}

public static void setSrc(File srcFile) {

src = srcFile;

if(srcFile.isDirectory())

srcSize = org.apache.commons.io.FileUtils.sizeOfDirectory(srcFile);

else

srcSize = src.length();

}

public static void setDes(File desFile) {

des = desFile;

desSize = 0;

}

public static void setSrc(Path srcPath)

{

setSrc(srcPath.toFile());

}

public static void setDes(Path desPath)

{

setDes(desPath.toFile());

}

private static void copyFile(File srcFile,File desFile) throws IOException

{

if (copyMethod[0])

copyByFileStream(srcFile,desFile);

else if (copyMethod[1])

copyByBufferStream(srcFile, desFile);

else if (copyMethod[2])

copyByFileReader(srcFile, desFile);

else if (copyMethod[3])

copyByBufferReader(srcFile, desFile);

else if (copyMethod[4])

copyByFileChannel(srcFile, desFile);

else if (copyMethod[5])

copyByFileChannelWithBuffer(srcFile, desFile);

else if (copyMethod[6])

copyByCommonsIO(srcFile, desFile);

else if (copyMethod[7])

copyByFiles(srcFile, desFile);

else

showMessage("复制失败,找不到复制方法.");

}

private static void showMessage(String message)

{

JOptionPane.showMessageDialog(null, message);

}

public static boolean haveSelectedSrcAndDes()

{

return src != null && des != null;

}

public static void copy()

{

long start = System.currentTimeMillis();

if(haveSelectedSrcAndDes())

{

if(src.isFile())

{

des = new File(des.getAbsolutePath()+File.separator+src.getName());

}

SwingWorker copyTask = new SwingWorker<>()

{

@Override

protected String doInBackground()

{

try

{

if (traverseMethod[0])

traverseByListFiles(src, des);

else if (traverseMethod[1])

traverseByList(src, des);

else if (traverseMethod[2])

traverseByGetFiles(src, des);

else if (traverseMethod[3])

traverseByCommonsIO(src, des);

else if (traverseMethod[4])

traverseByNIO2(src);

else

{

showProgressBar.dispose();

showMessage("遍历失败,找不到遍历方法");

}

}

catch (IOException e)

{

e.printStackTrace();

showProgressBar.dispose();

showMessage("未知错误复制失败");

}

finish(start);

return null;

}

};

copyTask.execute();

if (!copyMethod[4] && !copyMethod[6] && !copyMethod[7])

{

copyProgressBar.setMinimum(0);

copyProgressBar.setMaximum(100);

copyProgressBar.setValue(0);

copyProgressBar.setVisible(true);

copyProgressBar.setStringPainted(true);

showProgressBar.add(copyProgressBar);

showProgressBar.setTitle("复制进度");

showProgressBar.setBounds((int) (Toolkit.getDefaultToolkit().getScreenSize().getWidth() / 2) - 150,

(int) (Toolkit.getDefaultToolkit().getScreenSize().getHeight() / 2) - 50, 300, 100);

showProgressBar.setVisible(true);

new Thread(

() ->

{

int percent;

while ((percent = getCopyPercent()) < 100)

{

try

{

Thread.sleep(100);

}

catch(InterruptedException e)

{

e.printStackTrace();

}

copyProgressBar.setValue(percent);

}

}

).start();

}

else

{

final String [] text = {".","..","...","....",".....",".......","......",".....","....","...","..","."};

textField.setVisible(true);

textField.setHorizontalAlignment(JTextField.CENTER);

textField.setEditable(false);

showProgressBar.add(textField);

showProgressBar.setTitle("复制中");

showProgressBar.setBounds((int) (Toolkit.getDefaultToolkit().getScreenSize().getWidth() / 2) - 120,

(int) (Toolkit.getDefaultToolkit().getScreenSize().getHeight() / 2) - 40, 240, 80);

showProgressBar.setVisible(true);

new Thread(

() ->

{

while (getCopyPercent() < 100)

{

try

{

Thread.sleep(400);

}

catch(InterruptedException e)

{

e.printStackTrace();

}

if(index < text.length)

textField.setText("复制中"+text[index++]);

else

index = 0;

}

}

).start();

}

}

}

private static void finish(long start)

{

long end = System.currentTimeMillis();

showProgressBar.dispose();

showMessage("复制成功,用时:" + (end - start) / 1000.0 + "s");

copyProgressBar.setVisible(false);

showProgressBar.remove(copyProgressBar);

textField.setVisible(false);

showProgressBar.remove(textField);

Arrays.fill(traverseMethod, false);

Arrays.fill(copyMethod, false);

des = src = null;

desSize = srcSize;

}

}

java 多种类型文件复制_java多种文件复制方式以及效率比较相关推荐

  1. java 写入文件流_Java实现文件写入——IO流

    输入输出的重要性: 输入和输出功能是Java对程序处理数据能力的提高,Java以流的形式处理数据.流是一组有序的数据序列,根据操作的类型,分为输入流和输出流. 程序从输入流读取数据,向输出流写入数据. ...

  2. java生成word文档_Java多种方式动态生成doc文档

    本来是要在Android端生成doc的(这需求...),最后方法没有好的方法能够在Android上做到完美,最后还是只能搬迁到服务器.不浪费,还是记录下各框架不支持Android的原因以及他们的特点. ...

  3. java底层 文件操作_JAVA的文件操作【转】

    11.3 I/O类使用 由于在IO操作中,需要使用的数据源有很多,作为一个IO技术的初学者,从读写文件开始学习IO技术是一个比较好的选择.因为文件是一种常见的数据源,而且读写文件也是程序员进行IO编程 ...

  4. java图片上传下载_Java中文件上传下载 --使用Minio

    Minio模板类: @RequiredArgsConstructor public class MinioTemplate implements InitializingBean { private ...

  5. java 对文件签名_Java对文件进行数字签名

    一:需要包含的包 import java.security.*; import java.io.*; import java.util.*; import java.security.*; impor ...

  6. java图片上传下载_java实现文件的上传和下载

    1. servlet 如何实现文件的上传和下载? 1.1上传文件 参考自:http://blog.csdn.net/hzc543806053/article/details/7524491 通过前台选 ...

  7. java上传ftp数据丢失_Java:将文件上传到FTP问题(数据包丢失) - java

    我正在尝试将文件从Java应用程序传输到FTP服务器 该程序可以正常工作,文件已传输,但是当我在FTO文件夹中打开文件时,文件已损坏,我认为在文件传输过程中数据包丢失了.为什么?我该如何解决? 另一个 ...

  8. java实现文件名过滤器接口_Java使用文件过滤器FileFilter、FilenameFilter搜索文件

    搜索文件优化,使用文件过滤器来搜索文件 我们可以使用过滤器来实现在某一目录下指定文件格式的搜索 在File类中有两个和ListFiles重载的方法,方法的参数传递的就是过滤器 一.FileFilter ...

  9. java io文件操作_java IO 文件操作方法总结

    java IO 文件操作方法总结 对于输入输出的理解: 输入输出,以程序为参考点,外部数据进入程序,通过输入流完成.程序将数据给外部设备,通过输出流完成. 文件Io的操作 //获取文件 File fi ...

最新文章

  1. 智慧农业物联网云平台方案
  2. java 排序_Java中常见的排序算法有哪些?---选择排序
  3. android studio 显示图形_显示服务器实现(一)
  4. SLAM Cartographer(4)对象Node
  5. hdu 1232 畅通工程
  6. 全国计算机一级试题重难点,全国计算机等级考试一级MS选择题(重难点)部分.doc...
  7. Java Script 学习笔记 -- Ajax
  8. csv数据去重 python_数据去重_Python数据分析实战应用_数据挖掘与分析视频-51CTO学院...
  9. ASCII 码表对照 2
  10. 原理探究——空间平滑MUSIC算法
  11. ghost手动恢复linux,GHOST手动恢复系统(GHOST还原系统)步骤详解
  12. AD10封装库转到PADS封装库里
  13. win7自定义html为桌面,Win7系统自定义桌面主题的方法
  14. 5.2.1_2 普通心理学(彭冉玲第四版) - 第1章 心理学的研究对象和方法
  15. android看视频掉帧,玩游戏看视频经常卡顿不顺畅?你只需这几步
  16. 三维重建 | 单张RGB图片生成三维网格模型
  17. html 每一段首行缩进2字符,设置段落首行缩进2字符,html设置段落首行缩进
  18. Outlook无法打开 .ost文件损坏,卸载重装也恢复不了
  19. 申请https证书相关说明
  20. 解决MAC上Django连接Mysql django.db.utils.OperationalError: (2003, Can't connect to MySQL 的问题

热门文章

  1. 收发电子邮件属于计算机在方面的应用,计算机应用基础复习题(供参考).doc
  2. java 字符串编程题,JAVA 基础编程练习题7 【程序 7 处理字符串】
  3. pytorch 卷积网络入门实例
  4. python获取硬件信息
  5. deep_sort_face
  6. Async和Await如何简化异步编程几个实例
  7. task ':app:compileDebugJavaWithJavac'.错误
  8. python获取小时分钟
  9. torch cpu版加载权重
  10. 树莓派安装Ubuntu 18 64系统