讨论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负责将对象动态的注入到容器,从而达到 ...
随机推荐
- regsvr32 命令小集注册OCX控件,注册控件(包括十几个举例)
Regsvr32 进程文件: regsvr32 or regsvr32.exe 进程名称: Microsoft DLL Registration Service 英文描述: regsvr32.ex ...
- Lucene.Net 2.3.1开发介绍 —— 三、索引(二)
原文:Lucene.Net 2.3.1开发介绍 -- 三.索引(二) 2.索引中用到的核心类 在Lucene.Net索引开发中,用到的类不多,这些类是索引过程的核心类.其中Analyzer是索引建立的 ...
- 14.6.1 Creating InnoDB Tables 创建InnoDB 表:
14.6.1 Creating InnoDB Tables 创建InnoDB 表: 创建一个InnoDB 表,使用CREATE TABLE 语句,你不需要指定 ENGINE=InnoDB子句 如果In ...
- c++ __declspec关键字详细用法
c++ __declspec关键字详细用法 __declspec用于指定所给定类型的实例的与Microsoft相关的存储方式.其它的有关存储方式的修饰符如static与extern等是C和C++语言的 ...
- PPS2013校园招聘笔试题
转载请标明出处,原文地址:http://blog.csdn.net/hackbuteer1/article/details/11473405 一.简答题 (1)一位老师有2个推理能力很强的学生,他告诉 ...
- dsplib使用备忘
1. 到TI官网下载与自己的芯片对应的dsplib库 2. 在工程属性里添加dsplib的头文件路径,lib库路径 3. 在源文件中包含dsplib头文件,如果是在.cpp文件里调用,包含头文件时要用 ...
- DRP之Oracle_11g数据库安装
不知道大家在安装了Oracle数据库的时候有没有这样或那样的困惑,今天这篇文章就把Oracle数据库的安装过程理一下,作为总结,方便以后的学习. 首先,将下载的两个文件放在一个目录下解压,然后打开文件 ...
- poj 3304(直线与线段相交)
传送门:Segments 题意:线段在一个直线上的摄影相交 求求是否存在一条直线,使所有线段到这条直线的投影至少有一个交点 分析:可以在共同投影处作原直线的垂线,则该垂线与所有线段都相交<==& ...
- 【Java&Android开源库代码剖析】のAndroid-Universal-Image-Loader-part1
做Android app开发的同学应该都听说过或者用过nostra13的Android-Universal-Image-Loader开源库,它在图片异步加载.缓存和显示等方面提供了强大灵活的框架.之前 ...
- 诺贝尔物理学奖公布:LED灯将点亮了整个21世纪
很多其它精彩.破晓博客:点击打开链接 7日.在瑞典首都斯德哥尔摩,瑞典皇家科学院常任秘书诺尔马克(左二)宣布2014年诺贝尔物理学奖得主.新华社发 ■人物 中村修二 勇于追讨酬劳的科学家 被誉为&qu ...