在Java中复制文件的标准简洁方法?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/106770/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-11 08:22:59  来源:igfitidea点击:

Standard concise way to copy a file in Java?

javafilecopy

提问by Peter

It has always bothered me that the only way to copy a file in Java involves opening streams, declaring a buffer, reading in one file, looping through it, and writing it out to the other steam. The web is littered with similar, yet still slightly different implementations of this type of solution.

一直困扰着我,在 Java 中复制文件的唯一方法是打开流、声明缓冲区、读入一个文件、循环遍历它并将其写出到另一个流。网络上充斥着此类解决方案的类似但仍然略有不同的实现。

Is there a better way that stays within the bounds of the Java language (meaning does not involve exec-ing OS specific commands)? Perhaps in some reliable open source utility package, that would at least obscure this underlying implementation and provide a one line solution?

有没有更好的方法可以保持在 Java 语言的范围内(意思是不涉及执行操作系统特定的命令)?也许在一些可靠的开源实用程序包中,这至少会掩盖这个底层实现并提供单行解决方案?

采纳答案by delfuego

As toolkit mentions above, Apache Commons IO is the way to go, specifically FileUtils.copyFile(); it handles all the heavy lifting for you.

正如上面提到的工具包,Apache Commons IO 是要走的路,特别是FileUtils复制文件();它为您处理所有繁重的工作。

And as a postscript, note that recent versions of FileUtils (such as the 2.0.1 release) have added the use of NIO for copying files; NIO can significantly increase file-copying performance, in a large part because the NIO routines defer copying directly to the OS/filesystem rather than handle it by reading and writing bytes through the Java layer. So if you're looking for performance, it might be worth checking that you are using a recent version of FileUtils.

并且作为后记,请注意最近版本的 FileUtils(例如 2.0.1 版本)增加了使用 NIO 来复制文件;NIO 可以显着提高文件复制性能,这在很大程度上是因为 NIO 例程推迟直接复制到 OS/文件系统,而不是通过 Java 层读取和写入字节来处理它。因此,如果您正在寻找性能,那么检查您是否使用了 FileUtils 的最新版本可能是值得的。

回答by Josh

I would avoid the use of a mega api like apache commons. This is a simplistic operation and its built into the JDK in the new NIO package. It was kind of already linked to in a previous answer, but the key method in the NIO api are the new functions "transferTo" and "transferFrom".

我会避免使用像 apache commons 这样的大型 api。这是一个简单的操作,它内置在新的 NIO 包中的 JDK 中。它在之前的答案中已经链接到,但 NIO api 中的关键方法是新函数“transferTo”和“transferFrom”。

http://java.sun.com/javase/6/docs/api/java/nio/channels/FileChannel.html#transferTo(long,%20long,%20java.nio.channels.WritableByteChannel)

http://java.sun.com/javase/6/docs/api/java/nio/channels/FileChannel.html#transferTo(long,%20long,%20java.nio.channels.WritableByteChannel)

One of the linked articles shows a great way on how to integrate this function into your code, using the 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();
        }
    }
}

Learning NIO can be a little tricky, so you might want to just trust in this mechanic before going off and trying to learn NIO overnight. From personal experience it can be a very hard thing to learn if you don't have the experience and were introduced to IO via the java.io streams.

学习 NIO 可能有点棘手,因此您可能只想相信这个机制,然后再开始尝试在一夜之间学习 NIO。从个人经验来看,如果您没有经验并且通过 java.io 流被介绍到 IO,那么学习它可能是一件非常困难的事情。

回答by Brad at Kademi

Note that all of these mechanisms only copy the contents of the file, not the metadata such as permissions. So if you were to copy or move an executable .sh file on linux the new file would not be executable.

请注意,所有这些机制都只复制文件的内容,而不是权限等元数据。因此,如果您要在 linux 上复制或移动可执行的 .sh 文件,则新文件将无法执行。

In order to truly a copy or move a file, ie to get the same result as copying from a command line, you actually need to use a native tool. Either a shell script or JNI.

为了真正复制或移动文件,即获得与从命令行复制相同的结果,您实际上需要使用本机工具。shell 脚本或 JNI。

Apparently, this might be fixed in java 7 - http://today.java.net/pub/a/today/2008/07/03/jsr-203-new-file-apis.html. Fingers crossed!

显然,这可能在 java 7 - http://today.java.net/pub/a/today/2008/07/03/jsr-203-new-file-apis.html 中修复。手指交叉!

回答by Ryan

Available as standard in Java 7, path.copyTo: http://openjdk.java.net/projects/nio/javadoc/java/nio/file/Path.htmlhttp://java.sun.com/docs/books/tutorial/essential/io/copy.html

在 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

I can't believe it took them so long to standardise something so common and simple as file copying :(

我不敢相信他们花了这么长时间来标准化像文件复制这样常见和简单的东西:(

回答by Andrew McKinlay

Google's Guava library also has a copy method:

Google 的 Guava 库也有复制方法

public static void copy(File from,
                        File to)
                 throws IOException
Copies all the bytes from one file to another.

Warning:If torepresents an existing file, that file will be overwritten with the contents of from. If toand fromrefer to the samefile, the contents of that file will be deleted.

Parameters:from- the source fileto- the destination file

Throws:IOException- if an I/O error occurs IllegalArgumentException- if from.equals(to)

将所有字节从一个文件复制到另一个文件。

警告:如果to代表一个现有文件,该文件将被from. 如果tofrom引用同一个文件,则该文件的内容将被删除。

参数:from- 源文件to- 目标文件

抛出:IOException- 如果发生 I/O 错误 IllegalArgumentException- 如果from.equals(to)

回答by Scott

Now with Java 7, you can use the following try-with-resource syntax:

现在使用 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() );
    }
}

Or, better yet, this can also be accomplished using the new Files class introduced in Java 7:

或者,更好的是,这也可以使用 Java 7 中引入的新 Files 类来完成:

public static void copyFile( File from, File to ) throws IOException {
    Files.copy( from.toPath(), to.toPath() );
}

Pretty snazzy, eh?

很时髦吧?

回答by saji

Three possible problems with the above code:

上述代码可能存在的三个问题:

  1. If getChannel throws an exception, you might leak an open stream.
  2. For large files, you might be trying to transfer more at once than the OS can handle.
  3. You are ignoring the return value of transferFrom, so it might be copying just part of the file.
  1. 如果 getChannel 抛出异常,您可能会泄漏打开的流。
  2. 对于大文件,您可能尝试一次传输的文件数量超出操作系统的处理能力。
  3. 您忽略了 transferFrom 的返回值,因此它可能只是复制文件的一部分。

This is why org.apache.tools.ant.util.ResourceUtils.copyResourceis so complicated. Also note that while transferFrom is OK, transferTo breaks on JDK 1.4 on Linux (see Bug ID:5056395) – Jesse Glick Jan

这就是为什么org.apache.tools.ant.util.ResourceUtils.copyResource如此复杂。另请注意,虽然 transferFrom 没有问题,但在 Linux 上的 JDK 1.4 上 transferTo 会中断(请参阅错误 ID:5056395)– Jesse Glick Jan

回答by Balaji Paulrajan

If you are in a web application which already uses Spring and if you do not want to include Apache Commons IO for simple file copying, you can use FileCopyUtilsof the Spring framework.

如果您在一个已经使用 Spring 的 Web 应用程序中,并且如果您不想包含 Apache Commons IO 来进行简单的文件复制,则可以使用Spring 框架的FileCopyUtils

回答by Glen Best

  • These methods are performance-engineered (they integrate with operating system native I/O).
  • These methods work with files, directories and links.
  • Each of the options supplied may be left out - they are optional.
  • 这些方法是性能设计的(它们与操作系统本机 I/O 集成)。
  • 这些方法适用于文件、目录和链接。
  • 提供的每个选项都可以省略 - 它们是可选的。

The utility class

实用类

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;
    }
}

Copying a directory or file

复制目录或文件

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);

Moving a directory or file

移动目录或文件

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);

Copying a directory or file recursively

递归复制目录或文件

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 );

回答by Rakshi

To copy a file and save it to your destination path you can use the method below.

要复制文件并将其保存到目标路径,您可以使用以下方法。

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();
    }
}