一直困扰我的是,在Java中复制文件的唯一方法包括打开流,声明缓冲区,读入一个文件,循环遍历它,并将其写入到另一个steam。网络上充斥着类似的,但仍然略有不同的这类解决方案的实现。
是否有一种更好的方法能够保持在Java语言的范围内(即不涉及执行特定于操作系统的命令)?也许在一些可靠的开源实用程序包中,它至少会模糊这个底层实现,并提供一行解决方案?
一直困扰我的是,在Java中复制文件的唯一方法包括打开流,声明缓冲区,读入一个文件,循环遍历它,并将其写入到另一个steam。网络上充斥着类似的,但仍然略有不同的这类解决方案的实现。
是否有一种更好的方法能够保持在Java语言的范围内(即不涉及执行特定于操作系统的命令)?也许在一些可靠的开源实用程序包中,它至少会模糊这个底层实现,并提供一行解决方案?
当前回答
在Java 7中很容易…
File src = new File("original.txt");
File target = new File("copy.txt");
Files.copy(src.toPath(), target.toPath(), StandardCopyOption.REPLACE_EXISTING);
其他回答
根据我的测试,带缓冲区的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();
}
}
}
}
如果你在一个已经使用Spring的web应用程序中,如果你不想包含Apache Commons IO来进行简单的文件复制,你可以使用Spring框架的FileCopyUtils。
这里有三种方法,您可以轻松地复制文件与一行代码!
Java7:
java.nio.file.Files #副本
private static void copyFileUsingJava7Files(File source, File dest) throws IOException {
Files.copy(source.toPath(), dest.toPath());
}
公共汽车共享10:
文件实用程序#复制文件
private static void copyFileUsingApacheCommonsIO(File source, File dest) throws IOException {
FileUtils.copyFile(source, dest);
}
番石榴:
文件#复制
private static void copyFileUsingGuava(File source,File dest) throws IOException{
Files.copy(source,dest);
}
这些方法是经过性能设计的(它们与操作系统本机I/O集成)。 这些方法适用于文件、目录和链接。 提供的每个选项都可以省略——它们是可选的。
实用工具类
package com.yourcompany.nio;
class Files {
static int copyRecursive(Path source, Path target, boolean prompt, CopyOptions options...) {
CopyVisitor copyVisitor = new CopyVisitor(source, target, options).copy();
EnumSet<FileVisitOption> fileVisitOpts;
if (Arrays.toList(options).contains(java.nio.file.LinkOption.NOFOLLOW_LINKS) {
fileVisitOpts = EnumSet.noneOf(FileVisitOption.class)
} else {
fileVisitOpts = EnumSet.of(FileVisitOption.FOLLOW_LINKS);
}
Files.walkFileTree(source[i], fileVisitOpts, Integer.MAX_VALUE, copyVisitor);
}
private class CopyVisitor implements FileVisitor<Path> {
final Path source;
final Path target;
final CopyOptions[] options;
CopyVisitor(Path source, Path target, CopyOptions options...) {
this.source = source; this.target = target; this.options = options;
};
@Override
FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes attrs) {
// before visiting entries in a directory we copy the directory
// (okay if directory already exists).
Path newdir = target.resolve(source.relativize(dir));
try {
Files.copy(dir, newdir, options);
} catch (FileAlreadyExistsException x) {
// ignore
} catch (IOException x) {
System.err.format("Unable to create: %s: %s%n", newdir, x);
return SKIP_SUBTREE;
}
return CONTINUE;
}
@Override
public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) {
Path newfile= target.resolve(source.relativize(file));
try {
Files.copy(file, newfile, options);
} catch (IOException x) {
System.err.format("Unable to copy: %s: %s%n", source, x);
}
return CONTINUE;
}
@Override
public FileVisitResult postVisitDirectory(Path dir, IOException exc) {
// fix up modification time of directory when done
if (exc == null && Arrays.toList(options).contains(COPY_ATTRIBUTES)) {
Path newdir = target.resolve(source.relativize(dir));
try {
FileTime time = Files.getLastModifiedTime(dir);
Files.setLastModifiedTime(newdir, time);
} catch (IOException x) {
System.err.format("Unable to copy all attributes to: %s: %s%n", newdir, x);
}
}
return CONTINUE;
}
@Override
public FileVisitResult visitFileFailed(Path file, IOException exc) {
if (exc instanceof FileSystemLoopException) {
System.err.println("cycle detected: " + file);
} else {
System.err.format("Unable to copy: %s: %s%n", file, exc);
}
return CONTINUE;
}
}
正在复制目录或文件
long bytes = java.nio.file.Files.copy(
new java.io.File("<filepath1>").toPath(),
new java.io.File("<filepath2>").toPath(),
java.nio.file.StandardCopyOption.REPLACE_EXISTING,
java.nio.file.StandardCopyOption.COPY_ATTRIBUTES,
java.nio.file.LinkOption.NOFOLLOW_LINKS);
移动目录或文件
long bytes = java.nio.file.Files.move(
new java.io.File("<filepath1>").toPath(),
new java.io.File("<filepath2>").toPath(),
java.nio.file.StandardCopyOption.ATOMIC_MOVE,
java.nio.file.StandardCopyOption.REPLACE_EXISTING);
递归复制目录或文件
long bytes = com.yourcompany.nio.Files.copyRecursive(
new java.io.File("<filepath1>").toPath(),
new java.io.File("<filepath2>").toPath(),
java.nio.file.StandardCopyOption.REPLACE_EXISTING,
java.nio.file.StandardCopyOption.COPY_ATTRIBUTES
java.nio.file.LinkOption.NOFOLLOW_LINKS );
快速和工作与所有版本的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();
}