我们一般比较两个文件中的对象是相同的文件,通常使用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. 【Unity3D】【NGUI】UILabel

    原文:http://www.tasharen.com/forum/index.php?topic=6706.0 NGUI讨论群:333417608 概述 UILabel是用来显示文本的脚本,继承自UI ...

  2. mybatis 的简单使用

    须要用到的包:(这里仅仅是当中一个版本号.其它的百度) mysql-connector-java-5.1.6-bin mybatis-3.2.2 先看项目文件夹: 配置文件mybatisconfig. ...

  3. sqlserver 自学笔记 函数实训 学分学期转换函数的设计

    设计目的: 1.运用sql基本知识,编写学期转换函数. 2.运用sql基本知识,编写学分转换函数,将考试成绩转换为学分 3.通过上述函数的编写与调试,熟练掌握 sql函数的编写.调试与使用方法. 设计 ...

  4. Java魔法堂:JVM的运行模式 (转)

    一.前言 JVM有Client和Server两种运行模式.不同的模式对应不同的应用场景,而JVM也会有相应的优化.本文将记录JVM模式的信息,以便日后查阅. 二.介绍 在$JAVA_HOME/jre/ ...

  5. IE网页js语法错误2行字符1,FF中正常

    今天开发过程中,突然遇到此奇葩问题,我之前以为是我js打开模态窗体传递的url参数有问题,我使用open没问题.使用模态窗体则会先弹出此错误然后再显示新打开的界面.网上查了许久,总结解决方案如下: 1 ...

  6. thinkphp 3.2.3 入门示例

    原文:thinkphp3.2 1.安装WAMPServer,到D:\wamp\. 2.下载ThinkPHP3.2.3核心版.解压缩后,放到D:\wamp\www\MyWeb\.打开浏览器,输入网址:h ...

  7. 从零开始,使用python快速开发web站点(2)

    书接上文.http://blog.csdn.net/i7788/article/details/10306595 首先是数据库的搭建,这里的django的数据模型搭建十分easy. no sql.ju ...

  8. oracle 通过查询灵活插入数据 insert into ...select..

    insert into reg_user (id,name,password,area_code,reg_time,first_pswd,record_type) select l.reg_user_ ...

  9. hdu4513(manacher)

    传送门:吉哥系列故事——完美队形II 题意:求最长回文队伍且队伍由中间向两边递减. 分析:manach算法小应用,在判断回文子串向两边递减时加点限制使回文是由中间向两边递减的. #pragma com ...

  10. poj1459(最大流)

    传送门:Power Network 题意:在一个网络图中有n个点,其中有np个发电站,nc个用户,m条电线;每个发电站,用户,和电线都对应有一个最大的电流;让求出该网络中最大的电流. 分析:最大流裸题 ...