我们一般比较两个文件中的对象是相同的文件,通常使用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 path
return 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 same
return (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. 请慎用java的File#renameTo(File)方法

    转载地址:http://xiaoych.iteye.com/blog/149328 以前我一直以为File#renameTo(File)方法与OS下面的 move/mv 命令是相同的,可以达到改名.移 ...

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

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

  3. Android Studio 关联 JDK Java 源码

    Android Studio 关联 Android 源码比较方便,一般下载后可自动关联,但是 Android Studio 默认使用的 JDK 是内嵌的,是不带源码的.所以在查看 JDK 源码时,看到 ...

  4. Java JDK和IntelliJ IDEA 配置及安装

    序言 初学java,idea走一波先.安装完成,配置配置项. idea 软件 官方下载地址:https://www.jetbrains.com/idea/download/#section=windo ...

  5. 01 IO流(一)—— 流的概念、File类

    1 流的概念理解(重要) 理解流的概念非常重要. 流,就是程序到数据源或目的地的一个通道. 我们把这个通道实例化得到一个具体的流,相当于一个数据传输工具,它可以在程序与资源之间进行数据交换. 换言之, ...

  6. BEA WebLogic平台下J2EE调优攻略--转载

    BEA WebLogic平台下J2EE调优攻略   2008-06-25 作者:周海根 出处:网络   前 言 随着近来J2EE软件广泛地应用于各行各业,系统调优也越来越引起软件开发者和应用服务器提供 ...

  7. AOP的实现原理——动态代理

    IOC负责将对象动态的 注入到容器,从而达到一种需要谁就注入谁,什么时候需要就什么时候注入的效果,可谓是招之则来,挥之则去.想想都觉得爽,如果现实生活中也有这本事那就爽 歪歪了,至于有多爽,各位自己脑 ...

  8. JDBC连接数据库经验技巧(转)

    Java数据库连接(JDBC)由一组用 Java 编程语言编写的类和接口组成.JDBC 为工具/数据库开发人员提供了一个标准的 API,使他们能够用纯Java API 来编写数据库应用程序.然而各个开 ...

  9. 新秀学习SSH(十四)——Spring集装箱AOP其原理——动态代理

    之前写了一篇文章IOC该博客--<Spring容器IOC解析及简单实现>,今天再来聊聊AOP.大家都知道Spring的两大特性是IOC和AOP. IOC负责将对象动态的注入到容器,从而达到 ...

随机推荐

  1. regsvr32 命令小集注册OCX控件,注册控件(包括十几个举例)

    Regsvr32 进程文件: regsvr32 or regsvr32.exe  进程名称: Microsoft DLL Registration Service  英文描述: regsvr32.ex ...

  2. Lucene.Net 2.3.1开发介绍 —— 三、索引(二)

    原文:Lucene.Net 2.3.1开发介绍 -- 三.索引(二) 2.索引中用到的核心类 在Lucene.Net索引开发中,用到的类不多,这些类是索引过程的核心类.其中Analyzer是索引建立的 ...

  3. 14.6.1 Creating InnoDB Tables 创建InnoDB 表:

    14.6.1 Creating InnoDB Tables 创建InnoDB 表: 创建一个InnoDB 表,使用CREATE TABLE 语句,你不需要指定 ENGINE=InnoDB子句 如果In ...

  4. c++ __declspec关键字详细用法

    c++ __declspec关键字详细用法 __declspec用于指定所给定类型的实例的与Microsoft相关的存储方式.其它的有关存储方式的修饰符如static与extern等是C和C++语言的 ...

  5. PPS2013校园招聘笔试题

    转载请标明出处,原文地址:http://blog.csdn.net/hackbuteer1/article/details/11473405 一.简答题 (1)一位老师有2个推理能力很强的学生,他告诉 ...

  6. dsplib使用备忘

    1. 到TI官网下载与自己的芯片对应的dsplib库 2. 在工程属性里添加dsplib的头文件路径,lib库路径 3. 在源文件中包含dsplib头文件,如果是在.cpp文件里调用,包含头文件时要用 ...

  7. DRP之Oracle_11g数据库安装

    不知道大家在安装了Oracle数据库的时候有没有这样或那样的困惑,今天这篇文章就把Oracle数据库的安装过程理一下,作为总结,方便以后的学习. 首先,将下载的两个文件放在一个目录下解压,然后打开文件 ...

  8. poj 3304(直线与线段相交)

    传送门:Segments 题意:线段在一个直线上的摄影相交 求求是否存在一条直线,使所有线段到这条直线的投影至少有一个交点 分析:可以在共同投影处作原直线的垂线,则该垂线与所有线段都相交<==& ...

  9. 【Java&Android开源库代码剖析】のAndroid-Universal-Image-Loader-part1

    做Android app开发的同学应该都听说过或者用过nostra13的Android-Universal-Image-Loader开源库,它在图片异步加载.缓存和显示等方面提供了强大灵活的框架.之前 ...

  10. 诺贝尔物理学奖公布:LED灯将点亮了整个21世纪

    很多其它精彩.破晓博客:点击打开链接 7日.在瑞典首都斯德哥尔摩,瑞典皇家科学院常任秘书诺尔马克(左二)宣布2014年诺贝尔物理学奖得主.新华社发 ■人物 中村修二 勇于追讨酬劳的科学家 被誉为&qu ...