Java 将匹配模式的文件从多个文件夹复制到另一个文件夹

Java copy files matching pattern from many folders to another folder

请查看我目前的代码,如果可能请解释我做错了什么。我正在努力学习。

我做了一个小程序,在一个目录及其所有子目录中搜索一种类型的文件,并将它们复制到另一个文件夹中。

代码

import java.util.ArrayList;
import java.util.List;
import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.StandardCopyOption;

public class FandFandLoop {

    public static void main(String[] args) {

        final File folder = new File("C:/Users/ina/src");

        List<String> result = new ArrayList<>();

        search(".*\.txt", folder, result);

        File to = new File("C:/Users/ina/dest");

        for (String s : result) {
            System.out.println(s);
            File from = new File(s);
            try {
                copyDir(from.toPath(), to.toPath());
                System.out.println("done");
            }
            catch (IOException ex) {
                ex.printStackTrace();
            }
        }

    }

    public static void copyDir(Path src, Path dest) throws IOException {
        Files.walk(src)
                .forEach(source -> {
                    try {
                        Files.copy(source, dest.resolve(src.relativize(source)),
                                        StandardCopyOption.REPLACE_EXISTING);
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                });
    }

    public static void search(final String pattern, final File folder, List<String> result) {
        for (final File f : folder.listFiles()) {

            if (f.isDirectory()) {
                search(pattern, f, result);
            }

            if (f.isFile()) {
                if (f.getName().matches(pattern)) {
                    result.add(f.getAbsolutePath());
                }
            }

        }
    }

}

它有效,但它实际做的是获取我的 .txt 文件并将它们写入另一个名为 dest 的不带扩展名的文件。

并且在某些时候,它会删除文件夹 dest

删除是因为StandardCopyOption.REPLACE_EXISTING,如果我理解这一点,但我想获得的是,如果多个文件具有相同的名称,那么只保留一份副本。

无需对匹配的源文件调用Files.walk

您可以通过完全切换到使用 java.nio.file.Path 而不是混合字符串路径和 File 对象来改进此代码。此外,您可以使用 Files.walk or even better Files.find.

而不是递归调用 File.listFiles()

因此您可以改为使用以下内容:

import java.io.IOException;
import java.io.UncheckedIOException;
import java.nio.file.CopyOption;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.PathMatcher;
import java.nio.file.Paths;
import java.nio.file.attribute.BasicFileAttributes;
import java.util.Objects;
import java.util.function.BiPredicate;
import java.util.stream.Stream;

public class CopyFiles {
    public static void copyFiles(Path src, Path dest, PathMatcher matcher, CopyOption... copyOptions) throws IOException {
        // Argument validation
        if (!Files.isDirectory(src)) {
            throw new IllegalArgumentException("Source '" + src + "' is not a directory");
        }
        if (!Files.isDirectory(dest)) {
            throw new IllegalArgumentException("Destination '" + dest + "' is not a directory");
        }
        Objects.requireNonNull(matcher);
        Objects.requireNonNull(copyOptions);

        BiPredicate<Path, BasicFileAttributes> filter = (path, attributes) -> attributes.isRegularFile() && matcher.matches(path);

        // Use try-with-resources to close stream as soon as it is not longer needed
        try (Stream<Path> files = Files.find(src, Integer.MAX_VALUE, filter)) {
            files.forEach(file -> {
                Path destFile = dest.resolve(src.relativize(file));
                try {
                    copyFile(file, destFile, copyOptions);
                }
                // Stream methods do not allow checked exceptions, have to wrap it
                catch (IOException ioException) {
                    throw new UncheckedIOException(ioException);
                }
            });
        }
        // Wrap UncheckedIOException; cannot unwrap it to get actual IOException 
        // because then information about the location where the exception was wrapped 
        // will get lost, see Files.find doc
        catch (UncheckedIOException uncheckedIoException) {
            throw new IOException(uncheckedIoException);
        }
    }

    private static void copyFile(Path srcFile, Path destFile, CopyOption... copyOptions) throws IOException {
        Path destParent = destFile.getParent();

        // Parent might be null if dest is empty path
        if (destParent != null) {
            // Create parent directories before copying file
            Files.createDirectories(destParent);
        }

        Files.copy(srcFile, destFile, copyOptions);
    }

    public static void main(String[] args) throws IOException {
        Path srcDir = Paths.get("path/to/src");
        Path destDir = Paths.get("path/to/dest");
        // Could also use FileSystem.getPathMatcher
        PathMatcher matcher = file -> file.getFileName().toString().endsWith(".txt");
        copyFiles(srcDir, destDir, matcher);
    }
}