您如何编写一个java函数boolean sameContent(Path file1,Path file2)
来确定两个给定路径是否指向存储相同内容的文件?当然,首先,我会检查文件大小是否相同。这是存储相同内容的必要条件。但后来我想听你的方法。如果这两个文件存储在同一个硬盘驱动器上(就像我的大多数情况一样),它可能不是在两个流之间跳转太多次的最好方法。
答案 0 :(得分:73)
Apache commons IO的FileUtils.contentEquals
方法究竟是什么,api是here。
尝试类似:
File file1 = new File("file1.txt");
File file2 = new File("file2.txt");
boolean isTwoEqual = FileUtils.contentEquals(file1, file2);
在实际进行比较之前,它会进行以下检查:
答案 1 :(得分:20)
如果您不想使用任何外部库,那么只需将文件读入字节数组并进行比较(在Java-7之前不起作用):
byte[] f1 = Files.readAllBytes(file1);
byte[] f2 = Files.readAllBytes(file2);
如果文件很大,那么您应该使用BufferedInputStream
而不是将整个文件读入数组,而是按照here的说明读取chunk-by-chunk文件。
答案 2 :(得分:11)
如果文件很小,你可以将两者都读入内存并比较字节数组。
如果文件不小,你可以一个接一个地计算其内容的哈希值(例如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;
}
答案 3 :(得分:4)
This可以帮助您解决问题:
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);
}
}
答案 4 :(得分:3)
如果用于单元测试,则Demo on 3v4l.org提供一种名为AssertJ的方法。一个例子:
Assertions.assertThat(file1).hasSameContentAs(file2)
答案 5 :(得分:0)
从Java 12开始,有一种方法Files.mismatch,如果文件内容中没有不匹配项,则该方法返回-1
。因此该函数如下所示:
private static boolean sameContent(Path file1, Path file2) throws IOException {
return Files.mismatch(file1, file2) == -1;
}
答案 6 :(得分:0)
我知道我参加这个聚会还很晚,但是如果您想使用直接的Java API并且没有第三方依赖性,那么内存映射IO是一种非常简单的方法。只需打开几个文件,映射它们,然后使用ByteBuffer.equals(Object)
比较文件即可。
如果您希望特定文件很大,那么这可能会给您带来最佳性能,因为您将大部分IO任务分担给OS和其他高度优化的JVM(假设您是使用体面的JVM)。
直接从 FileChannel JavaDoc:
对于大多数操作系统,将文件映射到内存比通过通常的读写方法读取或写入几十KB数据要昂贵。从性能的角度来看,通常只需要将较大的文件映射到内存中即可。
import java.io.IOException;
import java.nio.MappedByteBuffer;
import java.nio.channels.FileChannel;
import java.nio.file.Path;
import java.nio.file.StandardOpenOption;
public class MemoryMappedCompare {
public static boolean areFilesIdenticalMemoryMapped(final Path a, final Path b) throws IOException {
try (final FileChannel fca = FileChannel.open(a, StandardOpenOption.READ);
final FileChannel fcb = FileChannel.open(b, StandardOpenOption.READ)) {
final MappedByteBuffer mbba = fca.map(FileChannel.MapMode.READ_ONLY, 0, fca.size());
final MappedByteBuffer mbbb = fcb.map(FileChannel.MapMode.READ_ONLY, 0, fcb.size());
return mbba.equals(mbbb);
}
}
}
答案 7 :(得分:-1)
package test;
import org.junit.jupiter.api.Test;
import java.io.IOException;
import java.nio.file.FileSystems;
import java.nio.file.Files;
import java.nio.file.Path;
import static org.junit.Assert.assertEquals;
public class CSVResultDIfference {
@Test
public void csvDifference() throws IOException {
Path file_F = FileSystems.getDefault().getPath("C:\\Projekts\\csvTestX", "yolo2.csv");
long size_F = Files.size(file_F);
Path file_I = FileSystems.getDefault().getPath("C:\\Projekts\\csvTestZ", "yolo2.csv");
long size_I = Files.size(file_I);
assertEquals(size_F, size_I);
}
}
对我有用:)