Java文件等于
我不知道你们,但至少我预计f1会在下面的代码中等于f2,但显然情况并非如此! 你对此有何看法? 看来我必须编写自己的equals方法来支持它,对吗?
import java.io.*; public class FileEquals { public static void main(String[] args) { File f1 = new File("./hello.txt"); File f2 = new File("hello.txt"); System.out.println("f1: " + f1.getName()); System.out.println("f2: " + f2.getName()); System.out.println("f1.equals(f2) returns " + f1.equals(f2)); System.out.println("f1.compareTo(f2) returns " + f1.compareTo(f2)); } }
不是,事实并非如此。 因为equals是比较绝对路径的相等性(在你的情况下,它类似于:
some-project\.\hello.txt some-project\hello.txt
所以他们自然不同。
看来我必须编写自己的equals方法来支持它,对吗?
可能是。 但首先,你必须知道你想要比较什么? 只有路径名? 如果是,请以这种方式比较其规范路径:
f1.getCanonicalPath().equals(f2.getCanonicalPath())
但是如果你想比较两个不同文件的内容,那么是的 ,你应该编写自己的方法 – 或者只是从互联网上的某个地方复制。
要正确测试equals,必须调用getCanonicalFile()。 例如
public static void main(String[] args) throws IOException { File f1 = new File("./hello.txt").getCanonicalFile(); File f2 = new File("hello.txt").getCanonicalFile(); System.out.println("f1: " + f1.getAbsolutePath()); System.out.println("f2: " + f2.getAbsolutePath()); System.out.println("f1.equals(f2) returns " + f1.equals(f2)); System.out.println("f1.compareTo(f2) returns " + f1.compareTo(f2)); }
将为平等返回true。 请注意,getCanonicalFile可能会抛出IOException,因此我将其添加到方法签名中。
如果您只想比较每个文件的CONTENTS,可以将内容读入字节数组,如下所示:
byte[] f1 = Files.readAllBytes(file1); byte[] f2 = Files.readAllBytes(file2);
然后比较你想要的东西。
请注意,此方法调用仅存在于Java 7中。对于旧版本,Guava和Apache具有类似但具有不同名称和详细信息的方法。
编辑:或者更好的选择(特别是如果你要比较大文件)可能只是逐字节比较而不是将整个文件加载到内存中,如下所示:
FileInputStream f1 = new FileInputStream(file1); DataInputStream d1 = new DataInputStream(f1); FileInputStream f2 = new FileInputStream(file2); DataInputStream d2 = new DataInputStream(f2); byte b1 = d1.readByte(); byte b2 = d2.readByte();
然后从那里进行比较。
我发现两个文件差异的更快的方法如下。
这只是为了解决这个问题的主张。
不确定性能(如果文件每个10 GB怎么办?)
File file = new File("/tmp/file.txt"); File secondFile = new File("/tmp/secondFile.txt"); // Bytes diff byte[] b1 = Files.readAllBytes(file.toPath()); byte[] b2 = Files.readAllBytes(secondFile.toPath()); boolean equals = Arrays.equals(b1, b2); System.out.println("the same? " + equals); // List Diff List c1 = Files.readAllLines(file.toPath()); List c2 = Files.readAllLines(secondFile.toPath()); boolean containsAll = c1.containsAll(c2); System.out.println("the same? " + containsAll); }
编辑
但是,unix系统上的diff实用程序会更加快速和冗长。 取决于你需要比较的东西。
以下是两种方法的实现:
/** * Tests this abstract pathname for equality with the given object. * Returns
true
if and only if the argument is not *null
and is an abstract pathname that denotes the same file * or directory as this abstract pathname. Whether or not two abstract * pathnames are equal depends upon the underlying system. On UNIX * systems, alphabetic case is significant in comparing pathnames; on Microsoft Windows * systems it is not. * * @param obj The object to be compared with this abstract pathname * * @returntrue
if and only if the objects are the same; *false
otherwise */ public boolean equals(Object obj) { if ((obj != null) && (obj instanceof File)) { return compareTo((File)obj) == 0; } return false; }
/** * Compares two abstract pathnames lexicographically. The ordering * defined by this method depends upon the underlying system. On UNIX * systems, alphabetic case is significant in comparing pathnames; on Microsoft Windows * systems it is not. * * @param pathname The abstract pathname to be compared to this abstract * pathname * * @return Zero if the argument is equal to this abstract pathname, a * value less than zero if this abstract pathname is * lexicographically less than the argument, or a value greater * than zero if this abstract pathname is lexicographically * greater than the argument * * @since 1.2 */ public int compareTo(File pathname) { return fs.compare(this, pathname); }
如果您使用的是Windows,请参阅类Win32FileSystem
比较方法如下所示,因此您的文件对象不同是很正常的。
public int compare(File f1, File f2) { return f1.getPath().compareToIgnoreCase(f2.getPath()); }
将这些行添加到您的代码中
System.out.println(f1.getPath()); System.out.println(f2.getPath());
它会打印出来
.\hello.txt hello.txt
因此,它们不相等,因为使用File对象的路径proeprty进行比较
如果您只是想根据路径使用来检查文件是否相同
java.nio.file.Files#isSameFile
例如
Assert.assertTrue(Files.isSameFile( new File("some-project\.\hello.txt").toPath(), new File("some-project\hello.txt").toPath() ));