一直困扰我的是,用Java复制文件的唯一方法是打开流,声明一个缓冲区,读取一个文件,循环遍历它,然后将其写入另一个文件.Web上充斥着类似但仍然略有不同的此类解决方案的实现.
有没有更好的方法保持在Java语言的范围内(意味着不涉及执行特定于操作系统的命令)?也许在一些可靠的开源实用程序包中,这至少会掩盖这个底层实现并提供单行解决方案?
Jos*_*osh 277
我会避免使用像apache commons这样的mega api.这是一个简单的操作,它内置于新的NIO包中的JDK中.它在前一个答案中已经有点联系了,但是NIO api中的关键方法是新功能"transferTo"和"transferFrom".
其中一篇链接文章显示了如何使用transferFrom将此功能集成到代码中的一种很好的方法:
public static void copyFile(File sourceFile, File destFile) throws IOException {
if(!destFile.exists()) {
destFile.createNewFile();
}
FileChannel source = null;
FileChannel destination = null;
try {
source = new FileInputStream(sourceFile).getChannel();
destination = new FileOutputStream(destFile).getChannel();
destination.transferFrom(source, 0, source.size());
}
finally {
if(source != null) {
source.close();
}
if(destination != null) {
destination.close();
}
}
}
Run Code Online (Sandbox Code Playgroud)
学习NIO可能有点棘手,所以你可能想要在离开并试图一夜之间学习NIO之前就相信这个机制.根据个人经验,如果您没有经验并且通过java.io流引入IO,那么学习起来可能是一件非常困难的事情.
del*_*ego 273
正如上面提到的工具包,Apache Commons IO是可行的方法,特别是FileUtils.copyFile() ; 它为您处理所有繁重的工作.
并且作为附言,请注意最新版本的FileUtils(例如2.0.1版本)已经添加了使用NIO来复制文件; NIO可以显着提高文件复制性能,这在很大程度上是因为NIO例程将复制直接推迟到OS /文件系统而不是通过Java层读取和写入字节来处理它.因此,如果您正在寻找性能,可能需要检查您使用的是最新版本的FileUtils.
Sco*_*ott 180
现在使用Java 7,您可以使用以下try-with-resource语法:
public static void copyFile( File from, File to ) throws IOException {
if ( !to.exists() ) { to.createNewFile(); }
try (
FileChannel in = new FileInputStream( from ).getChannel();
FileChannel out = new FileOutputStream( to ).getChannel() ) {
out.transferFrom( in, 0, in.size() );
}
}
Run Code Online (Sandbox Code Playgroud)
或者,更好的是,这也可以使用Java 7中引入的新Files类来完成:
public static void copyFile( File from, File to ) throws IOException {
Files.copy( from.toPath(), to.toPath() );
}
Run Code Online (Sandbox Code Playgroud)
很时髦,是吗?
Gle*_*est 88
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;
}
}
Run Code Online (Sandbox Code Playgroud)
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);
Run Code Online (Sandbox Code Playgroud)
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);
Run Code Online (Sandbox Code Playgroud)
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 );
Run Code Online (Sandbox Code Playgroud)
Kev*_*ler 41
在Java 7中很容易......
File src = new File("original.txt");
File target = new File("copy.txt");
Files.copy(src.toPath(), target.toPath(), StandardCopyOption.REPLACE_EXISTING);
Run Code Online (Sandbox Code Playgroud)
Rak*_*shi 28
要复制文件并将其保存到目标路径,您可以使用以下方法.
public void copy(File src, File dst) throws IOException {
InputStream in = new FileInputStream(src);
try {
OutputStream out = new FileOutputStream(dst);
try {
// Transfer bytes from in to out
byte[] buf = new byte[1024];
int len;
while ((len = in.read(buf)) > 0) {
out.write(buf, 0, len);
}
} finally {
out.close();
}
} finally {
in.close();
}
}
Run Code Online (Sandbox Code Playgroud)
小智 24
请注意,所有这些机制仅复制文件的内容,而不复制权限等元数据.因此,如果您要在Linux上复制或移动可执行文件.sh文件,则新文件将无法执行.
为了真正复制或移动文件,即获得与从命令行复制相同的结果,您实际上需要使用本机工具.shell脚本或JNI.
显然,这可以在java 7中修复 - http://today.java.net/pub/a/today/2008/07/03/jsr-203-new-file-apis.html.手指交叉!
小智 19
在Java 7中标准提供,path.copyTo:http : //openjdk.java.net/projects/nio/javadoc/java/nio/file/Path.html http://java.sun.com/docs/books/教程/本质/ IO/copy.html
我无法相信它们花了这么长时间来标准化文件复制这么常见和简单的东西:(
小智 7
上述代码存在三个可能的问题:
这就是为什么org.apache.tools.ant.util.ResourceUtils.copyResource
这么复杂的原因.另请注意,虽然transferFrom正常,但是在Linux上的JDK 1.4上,transferTo会中断(参见错误ID:5056395) - Jesse Glick Jan
您可以通过以下三种方式轻松地使用单行代码复制文件!
Java7:
private static void copyFileUsingJava7Files(File source, File dest) throws IOException {
Files.copy(source.toPath(), dest.toPath());
}
Run Code Online (Sandbox Code Playgroud)
Appache Commons IO:
private static void copyFileUsingApacheCommonsIO(File source, File dest) throws IOException {
FileUtils.copyFile(source, dest);
}
Run Code Online (Sandbox Code Playgroud)
番石榴:
private static void copyFileUsingGuava(File source,File dest) throws IOException{
Files.copy(source,dest);
}
Run Code Online (Sandbox Code Playgroud)
小智 6
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();
}
}
}
Run Code Online (Sandbox Code Playgroud)