博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
讨论JDK的File.equal()
阅读量:6500 次
发布时间:2019-06-24

本文共 5163 字,大约阅读时间需要 17 分钟。

 

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

               

 

我们先看看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://zqvyo.baihongyu.com/

你可能感兴趣的文章
递归和迭代的差别
查看>>
基于jquery的可拖动div
查看>>
可以简易设置文字内边距的EdgeInsetsLabel
查看>>
[詹兴致矩阵论习题参考解答]习题1.3
查看>>
Android Fragment的使用
查看>>
沙朗javascript总结一下(一)---基础知识
查看>>
js深入研究之函数内的函数
查看>>
LeetCode:4_Median of Two Sorted Arrays | 求两个排序数组的中位数 | Hard
查看>>
python之commands模块
查看>>
android应用开发--------------看RadioGroup源代码,写相似单选选项卡的集成控件(如底部导航,tab等等)...
查看>>
LeetCode - Binary Tree Level Order Traversal
查看>>
FTP协议完全详解
查看>>
【C语言天天练(十五)】字符串输入函数fgets、gets和scanf
查看>>
【环境配置】配置sdk
查看>>
accept()
查看>>
USB 2.0 Hub IP Core
查看>>
USB 2.0 OTG IP Core
查看>>
解读浮动闭合最佳方案:clearfix
查看>>
Charles使用
查看>>
Python GUI编程(Tkinter) windows界面开发
查看>>