确定两个文件是否存储相同的内容

pri*_*ain 65 java comparison file

您如何编写一个java函数boolean sameContent(Path file1,Path file2)来确定两个给定路径是否指向存储相同内容的文件?当然,首先,我会检查文件大小是否相同.这是存储相同内容的必要条件.但后来我想听你的方法.如果这两个文件存储在同一个硬盘驱动器上(就像我的大多数情况一样),这可能不是在两个流之间跳转太多次的最佳方法.

SMA*_*SMA 81

究竟是什么FileUtils.contentEquals方法的Apache commons IO和api在这里.

尝试类似的东西:

File file1 = new File("file1.txt");
File file2 = new File("file2.txt");
boolean isTwoEqual = FileUtils.contentEquals(file1, file2);
Run Code Online (Sandbox Code Playgroud)

它在实际进行比较之前进行以下检查:

  • 存在两个文件
  • 传递的两个文件都是文件类型而不是目录.
  • 以字节为单位的长度不应该相同.
  • 两者都是不同的文件而不是同一个.
  • 然后比较内容.

  • 为了增加价值,我发现“FileUtils.contentEqualsIgnoreEOL”可能为不太严格的断言提供便利。 (3认同)

Cht*_*ect 24

如果您不想使用任何外部库,那么只需将文件读入字节数组并进行比较(在Java-7之前不起作用):

byte[] f1 = Files.readAllBytes(file1);
byte[] f2 = Files.readAllBytes(file2);
Run Code Online (Sandbox Code Playgroud)

通过使用Arrays.equals.

如果文件很大,那么不应该将整个文件读入数组,而应该BufferedInputStream按照此处的说明使用和读取chunk-by-chunk文件.

  • 我希望我的程序也能处理大文件。这可能会导致OutOfMemoryError-如果无法分配所需大小的数组,例如文件大于2GB。编辑:对不起,我刚刚看到您关于处理大文件的评论。 (2认同)
  • 真正.这就是为什么我包含一个SO页面的链接,它提到使用BufferedInputStream并读取chunk-by-chunk,而不是整个文件.没有必要重复SO中已经存在的答案. (2认同)

Nol*_*uen 14

从 Java 12 开始,有方法Files.mismatch-1如果文件内容没有不匹配,则返回该方法。因此,该函数将如下所示:

private static boolean sameContent(Path file1, Path file2) throws IOException {
    return Files.mismatch(file1, file2) == -1;
}
Run Code Online (Sandbox Code Playgroud)

  • 据我所知 - 不,它以 8kb 大小的块读取这两个文件。 (2认同)

icz*_*cza 12

如果文件很小,您可以将两者都读入内存并比较字节数组.

如果文件不小,您可以一个接一个地计算其内容的哈希值(例如MD5或SHA-1)并比较哈希值(但这仍然存在很小的错误机会),或者您可以比较它们内容,但为此你仍然必须交替阅读流.

这是一个例子:

boolean sameContent(Path file1, Path file2) throws IOException {
    final long size = Files.size(file1);
    if (size != Files.size(file2))
        return false;

    if (size < 4096)
        return Arrays.equals(Files.readAllBytes(file1), Files.readAllBytes(file2));

    try (InputStream is1 = Files.newInputStream(file1);
         InputStream is2 = Files.newInputStream(file2)) {
        // Compare byte-by-byte.
        // Note that this can be sped up drastically by reading large chunks
        // (e.g. 16 KBs) but care must be taken as InputStream.read(byte[])
        // does not neccessarily read a whole array!
        int data;
        while ((data = is1.read()) != -1)
            if (data != is2.read())
                return false;
    }

    return true;
}
Run Code Online (Sandbox Code Playgroud)

  • 我还不确定我们在同一页面上.我想通过简单地将`Files.newInputStream(file1)`更改为`new BufferedInputStream(Files.newInputStream(file1))`你的`is1.read()`调用将对应于一个简单的数组访问(在大多数情况下)和整个`read(byte [] ...)`的东西将在窗帘后面处理.因此,我建议您可以通过将输入流包装在"BufferedInputStreams"中来改进您的答案,并删除关于如何以额外的复杂性为代价加快速度的评论. (2认同)

mco*_*ive 7

如果用于单元测试,则AssertJ提供了一个名为hasSameContentAs的方法。一个例子:

Assertions.assertThat(file1).hasSameContentAs(file2)
Run Code Online (Sandbox Code Playgroud)

  • `hasSameContentAs`方法已被弃用,请改用 [hasSameBinaryContentAs](https://www.javadoc.io/static/org.assertj/assertj-core/3.19.0/org/assertj/core/api/AbstractFileAssert.html #hasSameTextualContentAs(java.io.File)): `assertThat(file1).hasSameBinaryContentAs(file2);` (2认同)

pet*_*mec 5

应该可以帮助您解决问题:

package test;

import java.io.File;
import java.io.IOException;

import org.apache.commons.io.FileUtils;

public class CompareFileContents {

    public static void main(String[] args) throws IOException {

        File file1 = new File("test1.txt");
        File file2 = new File("test2.txt");
        File file3 = new File("test3.txt");

        boolean compare1and2 = FileUtils.contentEquals(file1, file2);
        boolean compare2and3 = FileUtils.contentEquals(file2, file3);
        boolean compare1and3 = FileUtils.contentEquals(file1, file3);

        System.out.println("Are test1.txt and test2.txt the same? " + compare1and2);
        System.out.println("Are test2.txt and test3.txt the same? " + compare2and3);
        System.out.println("Are test1.txt and test3.txt the same? " + compare1and3);
    }
}
Run Code Online (Sandbox Code Playgroud)