我正在寻找一种有效的方法来检测两个 java.io.File
是否引用同一个物理文件。根据文档,File.equals()
应该完成这项工作:
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.
但是,给定一个挂载在/media/truecrypt1 的 FAT32 分区(实际上是一个 TrueCrypt 容器):
new File("/media/truecrypt1/File").equals(new File("/media/truecrypt1/file")) == false
你说这符合规范吗?在这种情况下,如何解决该问题?
更新:感谢评论者,对于 Java 7,我找到了适合我的 java.io.Files.isSameFile()
。
最佳答案
@Joachim 评论中的答案通常是正确的。确定两个 File
对象是否引用同一个操作系统文件的方法是使用 getCanonicalFile() 或 getCanonicalPath()。 javadoc 是这样说的:
"A canonical pathname is both absolute and unique. [...] Every pathname that denotes an existing file or directory has a unique canonical form."
所以下面的应该工作:
File f1 = new File("/media/truecrypt1/File"); // different capitalization ...
File f2 = new File("/media/truecrypt1/file"); // ... but same OS file (on Windows)
if (f1.getCanonicalPath().equals(f2.getCanonicalPath())) {
System.out.println("Files are equal ... no kittens need to die.");
}
但是,看起来您正在查看安装在 UNIX/Linux 上的 FAT32 文件系统。 AFAIK,Java 不知道这正在发生,只是对文件名应用通用的 UNIX/Linux 规则......在这种情况下会给出错误的答案。
如果这是真的发生的事情,我认为在纯 Java 6 中没有可靠的解决方案。但是,
您可以做一些复杂的 JNI 工作;例如获取文件描述符编号,然后在 native 代码中使用
fstat(2)
获取两个文件的设备和 inode 编号并进行比较的系统调用。Java 7
java.nio.file.Path.equals(Object)
看起来如果您调用resolve( )
在路径上首先解析符号链接(symbolic link)。 (从 javadoc 中可以看出,Linux 上每个已安装的文件系统是否都对应于一个不同的FileSystem
对象。)Java 7 教程有 this section查看两个
Path
对象是否针对同一个文件...建议使用java.nio.file.Files.isSameFile(Path, Path)
Would you say that this conforms to the specification?
不,是的。
从某种意义上说,
getCanonicalPath()
方法不会为每个现有的操作系统文件返回相同的值……这正是您阅读 javadoc 时所期望的。在技术意义上是的,Java 代码库(不是 javadoc)是最终规范......无论是在理论上还是在实践中。
关于Java, Linux : how to detect whether two java. io.Files引用同一个物理文件,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/5883221/