在Java中将文件从一个目录复制到另一个目录

182
我想使用Java从一个目录复制文件到另一个目录(子目录)。我有一个名为dir的目录,其中包含文本文件。我迭代dir中的前20个文件,并希望将它们复制到dir目录中的另一个目录(trainingDir),在迭代之前我已经创建了这个目录。
在代码中,我想将review(表示第i个文本文件或评审)复制到trainingDir。我该怎么做?似乎没有这样的函数(或者我找不到)。谢谢。
在代码中,我需要将review(表示第i个文本文件或review)复制到trainingDir中。请问有什么方法可以实现吗?我尝试查找相关函数但未果。谢谢。
boolean success = false;
File[] reviews = dir.listFiles();
String trainingDir = dir.getAbsolutePath() + "/trainingData";
File trDir = new File(trainingDir);
success = trDir.mkdir();
for(int i = 1; i <= 20; i++) {
    File review = reviews[i];

}

所以,您有一个充满文件的目录,并且您只想复制这些文件吗?输入端没有递归 - 例如将所有内容从子目录复制到主目录? - akarnokd
是的,没错。我对将这些文件复制或移动到另一个目录都很感兴趣(尽管在帖子中我只问了复制)。 - user42155
3
未来的更新:Java 7 版本增加了 Files 类中的一个特性,可以用于复制文件。这里有另一篇相关的帖子 https://dev59.com/qWQn5IYBdhLWcg3w9bCi。 - KevinL
34个回答

191

目前这应该可以解决你的问题

File source = new File("H:\\work-temp\\file");
File dest = new File("H:\\work-temp\\file2");
try {
    FileUtils.copyDirectory(source, dest);
} catch (IOException e) {
    e.printStackTrace();
}

FileUtils类来自apache commons-io库,从版本1.2开始提供。

使用第三方工具而不是自己编写所有实用程序似乎是一个更好的主意。这可以节省时间和其他有价值的资源。


FileUtils对我无效。我把源文件设置为“E:\Users\users.usr”,目标文件设置为“D:\users.usr”。问题可能是什么? - JAVA
5
很好的解决方案,对我来说,当我将FileUtils.copyDirectory(source, dest)更改为FileUtils.copyFile(source, dest)时就可以运行了,这样可以在目录不存在时创建目录。 - yuqizhang
FileUtils.copyDirectory 只复制目录中的文件,不包括子目录。FileUtils.copyDirectoryStructure 则会复制所有文件和子目录。 - Homayoun Behzadian

48

在Java 7中,有一个标准的方法可以复制文件:

Files.copy.

它与操作系统本地I/O集成,具有高性能。

有关用法的完整说明,请参见我在 Standard concise way to copy a file in Java?上的回答。


8
这并未解决复制整个目录的问题。 - Charlie
是的,如果你遵循链接的话它可以……别忘了在Java中,“File”可以代表目录或文件,它只是一个引用。 - gagarwa
1
如果该文件是一个目录,则在目标位置创建一个空目录(目录中的条目不会被复制)。 - yurez

45

标准API中没有文件复制方法(至少目前还没有)。你的选择有:

  • 自己编写,使用FileInputStream、FileOutputStream和缓冲区将字节从一个文件复制到另一个文件 - 或者更好的办法是使用FileChannel.transferTo()
  • 使用Apache Commons的FileUtils
  • 等待Java 7 中的NIO2

+1 for NIO2:最近我正在尝试使用NIO2/Java7,新的Path非常精良设计。 - dfa
好的,怎么在Java 7中实现呢?NIO2的链接现在已经失效了。 - ripper234
5
链接已修复。请注意,我是通过在谷歌中输入“java nio2”来找到新链接的。 - Michael Borgwardt
对于Apache Commons链接,我认为您的意思是链接到“#copyDirectory (java.io.File,java.io.File)”。 - kostmo

31

以下示例来自Java Tips,非常简单直接。我已经转而使用Groovy来处理文件系统操作-更加轻松和优雅。但这是我过去使用的Java Tips。它缺少健壮的异常处理,无法完全保证安全。

 public void copyDirectory(File sourceLocation , File targetLocation)
    throws IOException {

        if (sourceLocation.isDirectory()) {
            if (!targetLocation.exists()) {
                targetLocation.mkdir();
            }

            String[] children = sourceLocation.list();
            for (int i=0; i<children.length; i++) {
                copyDirectory(new File(sourceLocation, children[i]),
                        new File(targetLocation, children[i]));
            }
        } else {

            InputStream in = new FileInputStream(sourceLocation);
            OutputStream out = new FileOutputStream(targetLocation);

            // Copy the bits from instream to outstream
            byte[] buf = new byte[1024];
            int len;
            while ((len = in.read(buf)) > 0) {
                out.write(buf, 0, len);
            }
            in.close();
            out.close();
        }
    }

谢谢,但我不想复制整个目录 - 只需要其中的文件。现在我遇到了错误信息java.io.FileNotFoundException: (trDir路径)(这是一个目录)。只有这么写。我使用了以下方法: copyDirectory(review, trDir); - user42155
谢谢,最好检查sourceLocation.exists()以防止java.io.FileNotFoundException - Sdghasemi

23
如果你想复制一个文件而不是移动它,你可以按照以下方式编写代码。
private static void copyFile(File sourceFile, File destFile)
        throws IOException {
    if (!sourceFile.exists()) {
        return;
    }
    if (!destFile.exists()) {
        destFile.createNewFile();
    }
    FileChannel source = null;
    FileChannel destination = null;
    source = new FileInputStream(sourceFile).getChannel();
    destination = new FileOutputStream(destFile).getChannel();
    if (destination != null && source != null) {
        destination.transferFrom(source, 0, source.size());
    }
    if (source != null) {
        source.close();
    }
    if (destination != null) {
        destination.close();
    }

}

嗨,我已经尝试过了,但是我收到了错误信息: java.io.FileNotFoundException: ...path to trDir... (Is a directory) 我的文件和文件夹中的所有内容似乎都没问题。你知道出了什么问题吗?为什么会出现这种情况? - user42155
但是,难道不是有一个Windows错误,导致transferFrom无法一次复制大于64MB的流吗?http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4938442修复http://www.rgagnon.com/javadetails/java-0064.html - akarnokd
我正在使用Ubuntu 8.10,所以这不应该是问题。 - user42155
如果您确定您的代码永远不会在不同的平台上运行。 - akarnokd
@gemm,destfile 必须是文件应该复制到的确切路径。这意味着包括新文件名,而不仅仅是您想要复制文件的目录。 - Janusz
@Janusz,你怎么使用这个方法来移动文件而不是复制它? - StuStirling

20

Apache Commons FileUtils很方便。 您可以执行以下操作。

  1. 将文件从一个目录复制到另一个目录。

    使用copyFileToDirectory(File srcFile, File destDir)

  2. 将目录从一个目录复制到另一个目录。

    使用copyDirectory(File srcDir, File destDir)

  3. 将一个文件的内容复制到另一个文件中

    使用static void copyFile(File srcFile, File destFile)


19

Spring Framework有许多类似于Apache Commons Lang的实用程序类。因此,有org.springframework.util.FileSystemUtils

File src = new File("/home/user/src");
File dest = new File("/home/user/dest");
FileSystemUtils.copyRecursively(src, dest);

10
File sourceFile = new File("C:\\Users\\Demo\\Downloads\\employee\\"+img);
File destinationFile = new File("\\images\\" + sourceFile.getName());

FileInputStream fileInputStream = new FileInputStream(sourceFile);
FileOutputStream fileOutputStream = new FileOutputStream(
                destinationFile);

int bufferSize;
byte[] bufffer = new byte[512];
while ((bufferSize = fileInputStream.read(bufffer)) > 0) {
    fileOutputStream.write(bufffer, 0, bufferSize);
}
fileInputStream.close();
fileOutputStream.close();

1
简洁、简单的答案-没有额外的依赖。 - Clocker
请问您能描述一下前两行的内容吗? - AVA

10

你似乎正在寻找简单的解决方案(这是一件好事)。我建议使用Apache Common's的FileUtils.copyDirectory

复制整个目录到新位置并保留文件日期。

此方法将指定的目录及其所有子目录和文件复制到指定的目标位置。目标位置是目录的新位置和名称。

如果目标目录不存在,则创建目标目录。如果目标目录已存在,则该方法会将源与目标合并,并以源为优先。

你的代码可能像这样简洁明了:

File trgDir = new File("/tmp/myTarget/");
File srcDir = new File("/tmp/mySource/");

FileUtils.copyDirectory(srcDir, trgDir);

嗨,我不想复制整个目录 - 只想复制其中的文件。 - user42155
基本上是一样的,不是吗?源目录中的所有文件最终都会出现在目标目录中。 - Stu Thompson
1
这是比读取和写入文件更好的方法。+1 - Optimus Prime

10

Java 8

Path sourcepath = Paths.get("C:\\data\\temp\\mydir");
Path destinationepath = Paths.get("C:\\data\\temp\\destinationDir");        
Files.walk(sourcepath)
         .forEach(source -> copy(source, destinationepath.resolve(sourcepath.relativize(source)))); 

复制方法

static void copy(Path source, Path dest) {
    try {
        Files.copy(source, dest, StandardCopyOption.REPLACE_EXISTING);
    } catch (Exception e) {
        throw new RuntimeException(e.getMessage(), e);
    }
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接