讨论JDK的File.equal()
我们一般比较两个文件中的对象是相同的文件,通常使用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()的更多相关文章
- 请慎用java的File#renameTo(File)方法
		转载地址:http://xiaoych.iteye.com/blog/149328 以前我一直以为File#renameTo(File)方法与OS下面的 move/mv 命令是相同的,可以达到改名.移 ... 
- 请慎用java的File#renameTo(File)方法(转)
		以前我一直以为File#renameTo(File)方法与OS下面的 move/mv 命令是相同的,可以达到改名.移动文件的目的.不过后来经常发现问题:File#renameTo(File)方法会返回 ... 
- Android Studio 关联 JDK Java 源码
		Android Studio 关联 Android 源码比较方便,一般下载后可自动关联,但是 Android Studio 默认使用的 JDK 是内嵌的,是不带源码的.所以在查看 JDK 源码时,看到 ... 
- Java JDK和IntelliJ IDEA 配置及安装
		序言 初学java,idea走一波先.安装完成,配置配置项. idea 软件 官方下载地址:https://www.jetbrains.com/idea/download/#section=windo ... 
- 01 IO流(一)—— 流的概念、File类
		1 流的概念理解(重要) 理解流的概念非常重要. 流,就是程序到数据源或目的地的一个通道. 我们把这个通道实例化得到一个具体的流,相当于一个数据传输工具,它可以在程序与资源之间进行数据交换. 换言之, ... 
- BEA WebLogic平台下J2EE调优攻略--转载
		BEA WebLogic平台下J2EE调优攻略 2008-06-25 作者:周海根 出处:网络 前 言 随着近来J2EE软件广泛地应用于各行各业,系统调优也越来越引起软件开发者和应用服务器提供 ... 
- AOP的实现原理——动态代理
		IOC负责将对象动态的 注入到容器,从而达到一种需要谁就注入谁,什么时候需要就什么时候注入的效果,可谓是招之则来,挥之则去.想想都觉得爽,如果现实生活中也有这本事那就爽 歪歪了,至于有多爽,各位自己脑 ... 
- JDBC连接数据库经验技巧(转)
		Java数据库连接(JDBC)由一组用 Java 编程语言编写的类和接口组成.JDBC 为工具/数据库开发人员提供了一个标准的 API,使他们能够用纯Java API 来编写数据库应用程序.然而各个开 ... 
- 新秀学习SSH(十四)——Spring集装箱AOP其原理——动态代理
		之前写了一篇文章IOC该博客--<Spring容器IOC解析及简单实现>,今天再来聊聊AOP.大家都知道Spring的两大特性是IOC和AOP. IOC负责将对象动态的注入到容器,从而达到 ... 
随机推荐
- centos6安装bt工具transmission
			centos6 install transmission 1. 安装所需的组件: yum -y install gcc gcc-c++ m4 make automake libtool gettex ... 
- PowerShell 在线教程 4
			PowerShell 在线教程 4 认识Powershell 介绍和安装 自定义控制台 快速编辑模式和标准模式 快捷键 管道和重定向 Powershell交互式 数学运算 执行外部命令 命令集 别 ... 
- 启动网页时候自己主动载入servlet假设不使用strus最经常使用的两种方式
			这是第一种使用的是onload方法当中的test是自己的servlet <html> <body onload = "test"> </body> ... 
- Codeforces Round #257 (Div. 2) B Jzzhu and Sequences
			Jzzhu has invented a kind of sequences, they meet the following property: You are given x and y, ple ... 
- 深入分析redis cluster 集群
			深入分析redis cluster 集群安装配置详解 下面小编来为各位介绍一篇深入分析redis cluster 集群安装配置详解,如果你希望做数据库集群就可以来看看此文章的哦. http://rub ... 
- Linux 多线程串口通信
			大概流程就是打开一个串口.然后进行串口设置.开启二个线程,一个线程写数据,另一个线程读数据. 代码如下: #include <stdio.h> #include <stdlib.h& ... 
- 居然还有FindFirstChangeNotification函数
			http://download.csdn.net/download/sololie/5966243 
- ADO面板上的控件简介
			ADO面板上的控件简介 一. TADOConnection组件该组件用于建立数据库的连接.ADO的数据源组件和命令组件可以通过该组件运行命令及数据库中提取数据等.该组件用于建立数据库的连接,该连接可被 ... 
- 136 - Ugly Numbers
			Ugly Numbers Ugly numbers are numbers whose only prime factors are 2, 3 or 5. The sequence 1, 2, 3 ... 
- CentOS7/RHEL7安装Redis步骤详解
			CentOS7/RHEL7安装Redis步骤详解 CentOS7/RHEL7安装Redis还是头一次测试安装了,因为centos7升级之后与centos6有比较大的区别了,下面我们就一起来看看Cent ... 
