前言
我们知道不同的操作系统有各自的文件系统,这些文件系统又存在很多差异,而Java 因为是跨平台的,所以它必须要统一处理这些不同平台文件系统之间的差异,才能往上提供统一的入口。
关于FileSystem类
JDK 里面抽象出了一个 FileSystem 来表示文件系统,不同的操作系统通过继承该类实现各自的文件系统,比如 Windows NT/2000 操作系统则为 WinNTFileSystem,而 unix-like 操作系统为 UnixFileSystem。
需要注意的一点是,WinNTFileSystem类 和 UnixFileSystem类并不是在同一个 JDK 里面,也就是说它们是分开的,你只能在 Windows 版本的 JDK 中找到 WinNTFileSystem,而在 Linux 版本的 JDK 中找到 UnixFileSystem,同样地,其他操作系统也有自己的文件系统实现类。
这里分成两个系列分析 JDK 对两种(Windows 和Linux)操作系统的文件系统的实现类,先讲 Windows操作系统,对应为 WinNTFileSystem 类。 由于篇幅较长,《JDK不同操作系统的FileSystem(Windows)》分为上中下篇,此为下篇。
继承结构
1 | 复制代码--java.lang.Object |
createFileExclusively方法
该方法用于创建文件,本地方法逻辑是,
- 将路径转成宽字符形式。
- 判断路径是否为系统保留设备名。
- 调用 CreateFileW 函数创建文件,使用了 CREATE_NEW 模式,仅仅在不存在该文件时才创建。
- 如果已经存在该文件,尽量不抛出异常,而是返回 false,此过程还会尝试读取该文件的属性,失败则抛IO异常。
1 | 复制代码public native boolean createFileExclusively(String path) |
list方法
该方法用于列出指定目录下的所有文件和目录,本地方法处理逻辑如下,
- 获取
java/lang/String
类对象,并检查不能为NULL。 - 获取 File 对象对应的路径。
- 按照路径长度重新分配空间并将路径拷贝到 search_path。
- 通过 GetFileAttributesW 函数获取指定路径的文件属性,如果得到 INVALID_FILE_ATTRIBUTES 或如果为目录则直接返回NULL。
- 去除尾部多余的空格。
- 在路径的尾部添加
*
或\*
。 - 通过 FindFirstFileW 函数获取到第一个文件。
- 接着通过 while 循环和 FindNextFileW 函数不断获取下一个文件,并将得到的文件名放到字符串数组中,而且文件名不能为
.
和..
。 - 返回文件名数组,其中可以看到文件名数组的初始长度为16,如果超过该长度后则按照原来长度的两倍重新创建字符串数组对象,再将原数组复制到新数组中。
1 | 复制代码public native String[] list(File f); |
createDirectory方法
该方法用来创建目录,本地方法很简单,就是获取 File 对象对应的路径,再调用 CreateDirectoryW 函数创建目录。
1 | 复制代码public native boolean createDirectory(File f); |
setLastModifiedTime方法
该方法用来设置文件或目录的最后修改时间,本地方法是先获取 File 对象对应的路径,再用 CreateFileW 函数打开指定文件或目录,最后用 SetFileTime 函数设置最后修改时间。
1 | 复制代码public native boolean setLastModifiedTime(File f, long time); |
setReadOnly方法
该方法用于将指定文件设置成只读。本地方法逻辑为,
- 获取 File 对象对应的路径。
- 通过 GetFileAttributesW 函数获取文件属性。
- 如果文件属于超链接或者快捷方式,则先获取对应的最终路径,然后再用 GetFileAttributesW 函数获取文件属性。
- 判断不为目录的话则通过 SetFileAttributesW 函数设置文件为只读,对应标识为 FILE_ATTRIBUTE_READONLY。
1 | 复制代码public native boolean setReadOnly(File f); |
delete方法
该方法用于删除 File 对象指定路径,需要将标准路径缓存和标准路径前缀缓存都清掉,然后调用本地方法 delete0 执行删除操作。
1 | 复制代码public boolean delete(File f) { |
本地方法先获取 File 对象对应的路径,然后再调用 removeFileOrDirectory 函数删除目录或文件。而 removeFileOrDirectory 函数的逻辑是先将指定路径文件或目录设置成 FILE_ATTRIBUTE_NORMAL,然后再用 GetFileAttributesW 函数获取文件属性,最后如果指定路径为目录则调用 RemoveDirectoryW 函数删除目录,如果是文件则调用 DeleteFileW 函数删除文件。
1 | 复制代码JNIEXPORT jboolean JNICALL |
rename方法
该方法用于重命名文件,需要将标准路径缓存和标准路径前缀缓存都清掉,然后调用本地方法 rename0 执行重命名操作。
1 | 复制代码public boolean rename(File f1, File f2) { |
本地方法分别先获取原来的文件路径和重命名的文件路径,再通过 _wrename 函数进行重命名操作。
1 | 复制代码JNIEXPORT jboolean JNICALL |
access方法
该方法用于检查指定路径文件或目录是否可读,这里主要是JVM层的权限检查,所以用的是 SecurityManager 安全管理器来检测。
1 | 复制代码private boolean access(String path) { |
listRoots方法
该方法用于获取可用的文件系统的根文件对象的数组。逻辑如下,
- 先通过 listRoots0 本地方法获取所有根文件。
- listRoots0 方法很简单,就是直接用 GetLogicalDrives 函数获取到操作系统的逻辑驱动器字符。需要注意的是 GetLogicalDrives 返回的是一个 int 类型,那么它是怎么表示驱动器字符的呢?其实也是通过位来标识,每一位对应表示一个逻辑驱动器是否存在,比如第一位如果是”1”则表示驱动器”A:”存在, 第二位如果是“1”则表示驱动器“B:”存在,以此类推。
- 得到所有驱动器字符后通过一个for循环遍历检测驱动器的访问权限,去掉无权限的驱动器,并统计一个有n个驱动器,这里只需要循环26次,因为最多就是26个大写字母。
- 实例化一个 File 数组,大小为n。
- 再次通过一个26次的循环遍历得到有权限的驱动器,根据此驱动器符号实例化一个 File 对象,添加到 File 数组中。
- 返回 File 数组。
1 | 复制代码public File[] listRoots() { |
getSpace方法
该方法用于获取文件空间大小,包括总空间大小、剩余空间大小和可用空间大小,Java 层分别用 SPACE_TOTAL = 0
SPACE_FREE = 1
SPACE_USABLE = 2
标识。要查询某个文件的根目录的某某空间大小则将对应的标识传入,通过 getSpace0 本地方法获得。
1 | 复制代码public long getSpace(File f, int t) { |
本地方法的逻辑是,
- 获取 File 对象对应的文件或目录路径。
- 通过 GetVolumePathNameW 函数获取指定路径对应的根路径。
- 通过 GetDiskFreeSpaceExW 函数将总空间大小、空闲空间大小和可用空间大小获取到。
- 根据传入的标识返回不同的指标,比如
SPACE_TOTAL
则返回总空间大小,其他类似。
1 | 复制代码JNIEXPORT jlong JNICALL |
getNameMax方法
该方法用于获取系统允许的最大文件名长度。在调用 getNameMax0 本地方法前会先做一些处理,如果路径时绝对路径,则获取根路径并加上 \\
。
1 | 复制代码public int getNameMax(String path) { |
本地方法中通过 GetVolumeInformationW 函数得到系统允许的最大文件名长度 maxComponentLength
1 | 复制代码JNIEXPORT jint JNICALL |
compare方法
该方法用于比较两个 File 对象,其实就是直接比较路径字符串。
1 | 复制代码public int compare(File f1, File f2) { |
hashCode方法
该方法用于获取 File 对象的哈希值,获取 File对象路径,再将字符串变成小写,再调用字符串的 hashCode 方法,最后与 1234321 进行异或运算,得到的值即为该文件的哈希值。
1 | 复制代码public int hashCode(File f) { |
以下是广告和相关阅读
=============广告时间===============
公众号的菜单已分为“分布式”、“机器学习”、“深度学习”、“NLP”、“Java深度”、“Java并发核心”、“JDK源码”、“Tomcat内核”等,可能有一款适合你的胃口。
鄙人的新书《Tomcat内核设计剖析》已经在京东销售了,有需要的朋友可以购买。感谢各位朋友。
=========================
相关阅读:
JDK不同操作系统的FileSystem(Windows)上篇
JDK不同操作系统的FileSystem(Windows)中篇
欢迎关注:
这里写图片描述
本文转载自: 掘金