我们一般比较两个文件中的对象是相同的文件,通常使用java.io.File.equal()。这里,equal()是不是文件内容的比较结果为。象是否指向同一个文件。

File的equal()方法。实际上调用了当前文件系统FileSystem的compareTo()。

    public boolean equals(Object obj) {if ((obj != null) && (obj instanceof File)) {return compareTo((File)obj) == 0;}return false;}static private FileSystem fs = FileSystem.getFileSystem();public int compareTo(File pathname) {return fs.compare(this, pathname);}

我们发现,java.io.FileSystem中没有对Unix/Linux的实现,仅仅有Win32FileSystem,所以都是默认调用的这个实现类。 它对文件的比較,事实上就是对文件名称和绝对路径的比較。

假设两个File对象有同样的getPath(),就觉得他们是同一个文件。并且能看出来,Windows是不区分大写和小写的。

如以下的java.io.Win32FileSystem.compare()。

    public int compare(File f1, File f2) {return f1.getPath().compareToIgnoreCase(f2.getPath());}

这样通过比較绝对路径来检验两个对象是否指向同一个文件的方法,能适用大部分的情况,但也要小心。比方说,在Linux以下,文件名称对大写和小写是敏感的,就不能ignore了。并且通过硬链接建立的文件,实质还是指向同一个文件的,可是在File.equal()中却为false。

所以在JDK1.7后引入了工具类java.nio.file.Files,能够通过isSameFile()来推断两个文件对象是否指向同一个文件。

    public boolean isSameFile(Path path, Path path2) throws IOException {return provider(path).isSameFile(path, path2); }private static FileSystemProvider provider(Path path) {return path.getFileSystem().provider();}

他是获取当前系统的provider,再调用其isSameFile()来校验的。以下的FileSystem的实现层次结构:

        java.nio.file.spi.FileSystemProvider

            sun.nio.fs.AbstractFileSystemProvider

                sun.nio.fs.UnixFileSystemProvider

                    sun.nio.fs.LinuxFileSystemProvider

                sun.nio.fs.WindowsFileSystemProvider

我们先看看UnixFileSystemProvider.isSameFile() 是怎么实现的:

    public boolean isSameFile(Path obj1, Path obj2) throws IOException {UnixPath file1 = UnixPath.toUnixPath(obj1);if (file1.equals(obj2))return true;file1.checkRead();file2.checkRead();UnixFileAttributes attrs1 = UnixFileAttributes.get(file1, true);UnixFileAttributes attrs2 = UnixFileAttributes.get(file2, true);return attrs1.isSameFile(attrs2);}

他先调用了UnixPath.equal(),然后检查两个文件的可读性,最后再调用了UnixFileAttributes.isSameFile()。

非常显然,他会先检查两个文件的绝对路径是否同样(大写和小写敏感),假设同样的话,就觉得两者是同一个文件。假设不同,再检查两个文件的iNode号。

这是Unix文件系统的特点,文件是通过iNode来标识的,仅仅要iNode号同样,就说明指向同一个文件。

所以能用在推断两个硬链接是否指向同一个文件。

------------------------UnixPath------------------------

    public boolean equals(Object ob) {if ((ob != null) && (ob instanceof UnixPath))return compareTo((Path)ob) == 0;    // compare two pathreturn false;}public int compareTo(Path other) {int len1 = path.length;int len2 = ((UnixPath) other).path.length;int n = Math.min(len1, len2);byte v1[] = path;byte v2[] = ((UnixPath) other).path;int k = 0;while (k < n) {int c1 = v1[k] & 0xff;int c2 = v2[k] & 0xff;if (c1 != c2)return c1 - c2;}return len1 - len2;}

------------------------UnixFileAttributes------------------------

    boolean isSameFile(UnixFileAttributes attrs) {return ((st_ino == attrs.st_ino) && (st_dev == attrs.st_dev));}

而对于Windows系统。也是大同小异,来看看WindowsFileSystemProvider.isSameFile(),WindowsPath.equal()和 WindowsFileAttributes.isSameFile()。

都是先推断文件绝对路径(忽略大写和小写),假设相等就觉得是同一个文件;假设不等就再进行底层推断。Windows底层文件的推断是检查磁盘号是否相等来完毕的。

------------------------ WindowsFileSystemProvider------------------------

    public boolean isSameFile(Path obj1, Path obj2) throws IOException {WindowsPath file1 = WindowsPath.toWindowsPath(obj1);if (file1.equals(obj2))return true;file1.checkRead();file2.checkRead();WindowsFileAttributes attrs1 =WindowsFileAttributes.readAttributes(h1); WindowsFileAttributes attrs2 =WindowsFileAttributes.readAttributes(h2);return WindowsFileAttributes.isSameFile(attrs1, attrs2);}

------------------------ WindowsPath ------------------------  

    public boolean equals(Object obj) {if ((obj != null) && (obj instanceof WindowsPath))return compareTo((Path)obj) == 0;return false;}public int compareTo(Path obj) {if (obj == null)throw new NullPointerException();String s1 = path;String s2 = ((WindowsPath)obj).path;int n1 = s1.length();int n2 = s2.length();int min = Math.min(n1, n2);for (int i = 0; i < min; i++) {char c1 = s1.charAt(i);char c2 = s2.charAt(i);if (c1 != c2) {c1 = Character.toUpperCase(c1);c2 = Character.toUpperCase(c2);if (c1 != c2)return c1 - c2;}}return n1 - n2;}

------------------------ WindowsFileAttributes------------------------

    static boolean isSameFile(WindowsFileAttributes attrs1, WindowsFileAttributes attrs2) {// volume serial number and file index must be the samereturn (attrs1.volSerialNumber == attrs2.volSerialNumber) &&(attrs1.fileIndexHigh == attrs2.fileIndexHigh) &&(attrs1.fileIndexLow == attrs2.fileIndexLow);}

    

这样一比較就清晰了。假设仅仅是对照文件的绝对路径是否相等(不是内容)。能够放心使用File.equal()。而假设要比較在OS中是否指向同一个文件。能够使用Files.isSameFile()。它考虑到了不同文件系统的差异。同一时候。我们通过观察这两种系统校验规则的不同实现,也能窥视到不同OS文件系统的差异。假设你有兴趣,能够进一步深入研究哦!

最后,付上一个OpenJava的源代码地址,你能够在里面找到JDK引用的非常多sun.xxx.xxx的源代码。比如上面提到的一系列sun.nio.fs.xxx。http://grepcode.com/file/repository.grepcode.com/java/root/jdk/openjdk/7-b147/sun/awt/shell/ShellFolder.java#ShellFolder.compareTo%28java.io.File%29

讨论JDK的File.equal()相关推荐

  1. ide 两个模块的jdk版本不一样_Java平台模块系统(3)- JDK工具

    在完成项目模块的源代码之后,我们需要编译和运行这些模块.大部分时候,我们都是在IDE上进行开发和测试,可以把编译和运行的工作交给IDE来完成.不过我们仍然可以用javac和java来分别编译和运行代码 ...

  2. jdk javac运行不了_Intellij IDEA搭建jdk源码阅读环境

    一.找到源码位置 直接找到jdk安装的目录,会看到src.zip的压缩包,这里面就是jdk的源码,例如下图: 在这里解压. 第一次尝试建议使用9或更早版本jdk的源码,否则易造成卡死. 二.Intel ...

  3. 如何在 ASP.Net Core 中使用 File Providers

    ASP.Net Core 为了便于获取文件和文件夹信息,监视文件变更, 在文件系统中提供了一个抽象层:File Providers, 这篇文章将会讨论如何使用 File Providers . Fil ...

  4. JDK动态代理和CGLIB动态代理的异同

    代理模式的概念和静态代理之前的文章已经说过了,没看过的可以点这里. 动态代理意义在于生成一个占位(又称为代理对象),用来代理真实的对象,来控制真实对象的访问. 举个例子,现在有一家软件公司,公司里面有 ...

  5. java renameto_请慎用java的File#renameTo(File)方法(转)

    以前我一直以为File#renameTo(File)方法与OS下面的 move/mv 命令是相同的,可以达到改名.移动文件的目的.不过后来经常发现问题:File#renameTo(File)方法会返回 ...

  6. java的File.renameTo(File)方法

    亲测可用,若有疑问请私信 以前我一直以为File#renameTo(File)方法与OS下面的 move/mv 命令是相同的,可以达到改名.移动文件的目的.不过后来经常发现问题:File#rename ...

  7. RobotFramework环境配置十七:数据驱动(Read Excel File)

    数据驱动 RIDE提供的库: Create List Get File Import Variables Template ExcelLibrary 自定义库:DataCenter.py Read D ...

  8. RobotFramework环境配置十八:数据驱动(Read CSV File)

    数据驱动 RIDE提供的库: Create List Get File Import Variables Template ExcelLibrary 自定义库:DataCenter.py Read D ...

  9. Mac搭建JDK源码阅读环境

    点赞再看,养成习惯,微信公众号搜索[虚竹讲程序经],获取更多技术干货! 想要读懂JDK源码,需要在自己电脑上搭建JDK的源码阅读环境,正所谓,工欲善其事,必先利其器.下面演示如何在Mac上结合Idea ...

最新文章

  1. 文件节点的linux指令,Java工程师必学的Linux命令(一)文件与目录管理
  2. PagingAndSortingRepository接口与 JpaRepository接口
  3. 几个常用的文本处理shell 命令:find、grep、xargs、sort、uniq、tr、cut、paste、wc、sed、awk
  4. Mysql京东的一道面试题目 比较综合
  5. c语言如何监控网卡信息,查看网卡信息及状态和网卡日志信息
  6. 2018-2019-1 20165205 20165233 实验二 固件程序设计
  7. Win7下部署Lepus企业级MySQL数据库监控
  8. json树状图可视化_12个流行的Python数据可视化库总结
  9. python画出roc曲线 auc计算逻辑_从scikitlearn(sklearn)的多类数据计算AUC和ROC曲线?...
  10. 仅此一文带您走入智能叮当的世界
  11. 全栈式python工程师培训课程
  12. C++化学元素周期表
  13. 什么是虚拟主机管理系统?
  14. 悟透Javascript(转载)
  15. python适合做网页吗_python是否适合网页编程详解
  16. python怎么读取石墨表格_石墨这种多人文档编辑协作如何用开源软件实现?
  17. 两栈共享存储空间(线性结构栈)
  18. Android——进程间通信方式
  19. Python3中True、False、None等含义详解
  20. 大数据毕业设计 基于时间序列的股票预测与分析系统 - 大数据分析

热门文章

  1. ISP【三】———— raw读取、不同格式图片差异
  2. 源码分析-GLSurfaceView的内部实现
  3. web高性能开发系列随笔
  4. 经典SQL自定义函数
  5. asp.net2.0如何加密数据库联接字符串
  6. VirtualBox安装64位Linux
  7. 【FFmpeg】便捷函数汇总(持续更新中...)
  8. ddr42400和2660混插_DDR4 2400和3000区别大吗 低频和高频内存性能差距对比
  9. windows linux rac,跨平台表空间传输(windows到linux RAC)
  10. Java项目:医院预约挂号系统(java+SpringBoot+Maven+Vue+mysql)