更有效的方法来比较两个巨大的目录并替换相同的文件

时间:2016-02-17 05:33:15

标签: java file

F:/original_imagesE:/resized_images

我有两个HDD ,其中包含很多目录和图像(jpg)文件,每个文件大小约为 1.5TB(原始)和400GB(调整大小)

每个文件名都相同但大小不同(已调整大小)。然后我必须用原件替换已调整大小的那些。不幸的是,每个目录层次结构完全不同。

我设法完成了这项工作,但这需要很长时间。我期待几天完成。它有两个循环(Files.walkFileTree()),只搜索从A到Z的匹配。根本不聪明。

public static void main(String[] args) throws IOException {
        FileWriter ostream = new FileWriter("result.txt");
        BufferedWriter out = new BufferedWriter(ostream);

        String fromDir = "F:/original_images";
        String toDir = "E:/resized_images";
        final Path source = Paths.get(fromDir);
        final Path target = Paths.get(toDir);

        Files.walkFileTree(source, EnumSet.of(FileVisitOption.FOLLOW_LINKS), Integer.MAX_VALUE,
                            new SimpleFileVisitor<Path>() {
            @Override
            public FileVisitResult visitFile(Path sourceFile,
                    BasicFileAttributes attrs) throws IOException {
                // if jpg (there are no jpeg)
                if(sourceFile.toString().toLowerCase().endsWith("jpg")) {

                    // search for the matching file                 
                    // start ** inner of [Files.walkFileTree()]
                    Files.walkFileTree(target, EnumSet.of(FileVisitOption.FOLLOW_LINKS), Integer.MAX_VALUE,
                            new SimpleFileVisitor<Path>() {
                        @Override
                        public FileVisitResult visitFile(Path Targetfile, BasicFileAttributes attrs) throws IOException {

                            if(sourceFile.getFileName().equals(Targetfile.getFileName())) {
                                out.write("replace : [" + sourceFile + "] -> [" + Targetfile + "]");
                                try {
                                    // copy..
                                    Files.copy(sourceFile, Targetfile, REPLACE_EXISTING);
                                }catch(Exception e) {
                                    out.write(e.toString());
                                }
                                // stop searching for this file.
                                return FileVisitResult.TERMINATE;
                            }else
                                return FileVisitResult.CONTINUE;
                        }
                    });
                    // end ** inner of [Files.walkFileTree()]
                }
                return FileVisitResult.CONTINUE;
            }
        });
        out.write("[completed folder] " + fromDir);
        out.close();
    }

我相信一定有更聪明的方法。

(我的猜测是将文件名存储在索引数组中,因为它比较快得多。)

你会怎么做?

更新(解决)

通过采用两个答案的想法,我终于来做了。

源代码太长而无法显示,但简洁的是:

  1. 循环&#39; resized_images&#39;并将files_info存储到hashmap中(key:file_name,value:full_Path)。

  2. loop&#39; original_images&#39;并将files_info存储到hashmap中(key:file_name,value:full_Path)。我为每个hashmap做了 每个子目录的效率。

  3. 比较并替换每个已调整大小的&#39;和&#39;原创&#39; HashMap中。

  4. 结果比以前快得多。大多数执行时间是复制文件时。除此之外,它只需不到10分钟。

2 个答案:

答案 0 :(得分:1)

我看待它的方式,有两个子问题:

  1. 根据通用条件创建地图,即文件名,例如&#34; A.JPG&#34;
  2. 根据文件名替换另一个目录中重新调整大小的文件名
  3. 在上面列出的方法中,您在源目录中递归迭代,让我们调用外部循环。然后对于源目录中的每个文件,您在目标目录中递归迭代,让我们调用内部循环。这是一个O(n2)(读作n平方的大哦)的方法。

    另一个简单的方法是,创建两个映射(Hashmap),其中key是文件名。因此,您必须分别递归地遍历这两个目录,即分开循环。

    然后遍历较小的hashmap,然后替换已调整大小的图像。

    这将是一种O(n)方法。随着n不断增长,您应该看到所花费的时间有了显着改善。

答案 1 :(得分:1)

正如Sanket Naik所提到的,为原始图像创建一个地图。我不确定您的实施有多好,但您可以轻松编辑mkyong中的this代码。

Map商店image_name.jpg中以keyits_directory作为值。例如,img1.jpg位于F:/original_images/dir1/dir2/dir3/下,相应的条目应为img1.jpg, /dir1/dir2/dir3/

然后,

for each entry in resized image directory{
    value = map.get(entry);
    replaceImage(path/to/entry/+entry, value+entry);
}