在Java中,想要复制文件的唯一方式似乎总是需要打开流、声明缓冲区、读取一个文件并对其进行循环处理,最后将其写入另一个流中。网络上有很多类似的解决方案,但都有些微不同。
是否有更好的方法可以在Java语言范围内实现(也就是不涉及执行特定于操作系统的命令)?也许有可靠的开源工具包可以提供一行代码的解决方案来隐藏底层实现细节?
在Java中,想要复制文件的唯一方式似乎总是需要打开流、声明缓冲区、读取一个文件并对其进行循环处理,最后将其写入另一个流中。网络上有很多类似的解决方案,但都有些微不同。
是否有更好的方法可以在Java语言范围内实现(也就是不涉及执行特定于操作系统的命令)?也许有可靠的开源工具包可以提供一行代码的解决方案来隐藏底层实现细节?
以上代码可能存在三个问题:
这就是为什么org.apache.tools.ant.util.ResourceUtils.copyResource
如此复杂。同时请注意,虽然transferFrom是可以的,但transferTo在Linux的JDK 1.4上会出现问题(参见Bug ID:5056395)- Jesse Glick Jan
public static void copyFile(File src, File dst) throws IOException
{
long p = 0, dp, size;
FileChannel in = null, out = null;
try
{
if (!dst.exists()) dst.createNewFile();
in = new FileInputStream(src).getChannel();
out = new FileOutputStream(dst).getChannel();
size = in.size();
while ((dp = out.transferFrom(in, p, size)) > 0)
{
p += dp;
}
}
finally {
try
{
if (out != null) out.close();
}
finally {
if (in != null) in.close();
}
}
}
以下是三种只需一行代码即可轻松复制文件的方法!
Java7:
private static void copyFileUsingJava7Files(File source, File dest) throws IOException {
Files.copy(source.toPath(), dest.toPath());
}
Appache Commons IO:
private static void copyFileUsingApacheCommonsIO(File source, File dest) throws IOException {
FileUtils.copyFile(source, dest);
}
Guava:
Files#copy 方法:
private static void copyFileUsingGuava(File source,File dest) throws IOException{
Files.copy(source,dest);
}
Files.copy
是用于从Path
到Stream
的。只需为从Path
到Path
添加参数StandardCopyOption.COPY_ATTRIBUTES
或StandardCopyOption.REPLACE_EXISTING
即可。 - Pimp Trizkit根据我的测试,使用缓冲区的NIO复制方式是最快的。以下是我在一个测试项目中的工作代码,可在https://github.com/mhisoft/fastcopy查看。
import java.io.Closeable;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;
import java.text.DecimalFormat;
public class test {
private static final int BUFFER = 4096*16;
static final DecimalFormat df = new DecimalFormat("#,###.##");
public static void nioBufferCopy(final File source, final File target ) {
FileChannel in = null;
FileChannel out = null;
double size=0;
long overallT1 = System.currentTimeMillis();
try {
in = new FileInputStream(source).getChannel();
out = new FileOutputStream(target).getChannel();
size = in.size();
double size2InKB = size / 1024 ;
ByteBuffer buffer = ByteBuffer.allocateDirect(BUFFER);
while (in.read(buffer) != -1) {
buffer.flip();
while(buffer.hasRemaining()){
out.write(buffer);
}
buffer.clear();
}
long overallT2 = System.currentTimeMillis();
System.out.println(String.format("Copied %s KB in %s millisecs", df.format(size2InKB), (overallT2 - overallT1)));
}
catch (IOException e) {
e.printStackTrace();
}
finally {
close(in);
close(out);
}
}
private static void close(Closeable closable) {
if (closable != null) {
try {
closable.close();
} catch (IOException e) {
if (FastCopy.debug)
e.printStackTrace();
}
}
}
}
快速并且可以与所有版本的Java和Android一起使用:
private void copy(final File f1, final File f2) throws IOException {
f2.createNewFile();
final RandomAccessFile file1 = new RandomAccessFile(f1, "r");
final RandomAccessFile file2 = new RandomAccessFile(f2, "rw");
file2.getChannel().write(file1.getChannel().map(FileChannel.MapMode.READ_ONLY, 0, f1.length()));
file1.close();
file2.close();
}
虽然有点晚了,但这里是使用不同文件复制方法复制文件所需时间的比较。我循环运行了这些方法10次,并取得了平均值。使用IO流进行文件传输似乎是最差的选择:
这里是方法列表:private static long fileCopyUsingFileStreams(File fileToCopy, File newFile) throws IOException {
FileInputStream input = new FileInputStream(fileToCopy);
FileOutputStream output = new FileOutputStream(newFile);
byte[] buf = new byte[1024];
int bytesRead;
long start = System.currentTimeMillis();
while ((bytesRead = input.read(buf)) > 0)
{
output.write(buf, 0, bytesRead);
}
long end = System.currentTimeMillis();
input.close();
output.close();
return (end-start);
}
private static long fileCopyUsingNIOChannelClass(File fileToCopy, File newFile) throws IOException
{
FileInputStream inputStream = new FileInputStream(fileToCopy);
FileChannel inChannel = inputStream.getChannel();
FileOutputStream outputStream = new FileOutputStream(newFile);
FileChannel outChannel = outputStream.getChannel();
long start = System.currentTimeMillis();
inChannel.transferTo(0, fileToCopy.length(), outChannel);
long end = System.currentTimeMillis();
inputStream.close();
outputStream.close();
return (end-start);
}
private static long fileCopyUsingApacheCommons(File fileToCopy, File newFile) throws IOException
{
long start = System.currentTimeMillis();
FileUtils.copyFile(fileToCopy, newFile);
long end = System.currentTimeMillis();
return (end-start);
}
private static long fileCopyUsingNIOFilesClass(File fileToCopy, File newFile) throws IOException
{
Path source = Paths.get(fileToCopy.getPath());
Path destination = Paths.get(newFile.getPath());
long start = System.currentTimeMillis();
Files.copy(source, destination, StandardCopyOption.REPLACE_EXISTING);
long end = System.currentTimeMillis();
return (end-start);
}