程序员潇然 发表于 2022-8-10 11:22:14

JavaIO之File详解 以及FileSystem WinNTFileSystem简介(三)

文件和目录路径名的抽象表示形式。

我们知道,对于不同的操作系统,文件路径的描述是不同的
比如
windows平台:用
linux平台:用/

File是Java为了这一概念提供的抽象描述,与系统无关的视图
**抽象路径名** 有两个组件:
1.可选的与系统有关的前缀字符串   比如盘符,"/" 表示 UNIX 中的根目录,"\\\\" 表示 Microsoft Windows UNC 路径名
2.零个或者多个字符串名称 序列

第一个名称是 目录名,第一个名称之后每个名称表示一个目录,最后一个名称既可以是目录,也可以是名称
空 抽象路径名没有前缀和名称序列

注意:
既然最后一个名称可以是目录,也可以是文件名称,那么File 并不一定就是一个文件,也可以是一个文件路径,也就是目录

### 构造方法

java中使用File来抽象表示 文件/目录这一个概念

也就是在Java中,想要表示一个文件,构造一个File对象即可

| 构造方法                                                            |
| --------------------------------------------------------------------- |
| File(File parent, String child)                                       |
| 根据 parent 抽象路径名和 child 路径名字符串创建一个新 File 实例。   |
| File(String pathname)                                                 |
| 通过将给定路径名字符串转换为抽象路径名来创建一个新 File 实例。      |
| File(String parent, String child)                                     |
| 根据 parent 路径名字符串和 child 路径名字符串创建一个新 File 实例。   |
| File(URI uri)                                                         |
| 通过将给定的 file: URI 转换为一个抽象路径名来创建一个新的 File 实例。 |

通过路径构造一个File,是最自然地做法

`File(File parent, String child)`根据参数file的路径和child字符串进行组合

`File(String parent, String child)`根据参数 parent字符串和child字符串组合

本质上也就还是路径,不过很显然,拼接 child 就可以进行创建子目录

URI是统一资源标识符,将文件转换成一个链接,可以网络访问,通过这个URI 也可以用来生成文件
URI是统一资源标识符,将文件转换成一个链接,可以网络访问 ,通过这个URI 也可以用来生成文件

new File只是在java中描述这么一个文件,是否真的存在? 你还需要进行去验证,只是一个虚拟的描述符

### 名称与路径的分隔符

另外File 中还包括两个分隔符

目录分隔符名称分隔符的两种形式char 和 String

| 方法                                                         | 说明                                                                                                                                                                                                            |
| ------------------------------------------------------------ | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| separatorChar public static final char separatorChar         | 与系统有关的默认名称分隔符。此字段被初始化为包含系统属性 file.separator 值的第一个字符。在 UNIX 系统上,此字段的值为 '/';在 Microsoft Windows 系统上,它为 '\\'。                                              |
| separator public static final String separator               | 与系统有关的默认名称分隔符,为了方便,它被表示为一个字符串。此字符串只包含一个字符,即 separatorChar。                                                                                                          |
| pathSeparatorChar public static final char pathSeparatorChar | 与系统有关的路径分隔符。此字段被初始为包含系统属性 path.separator 值的第一个字符。此字符用于分隔以路径列表 形式给定的文件序列中的文件名。在 UNIX 系统上,此字段为 ':';在Microsoft Windows 系统上,它为 ';'。 |
| pathSeparator public static final String pathSeparator       | 与系统有关的路径分隔符,为了方便,它被表示为一个字符串。此字符串只包含一个字符,即 pathSeparatorChar。                                                                                                          |

### File API分类

File既可能是目录,也可能是文件,所以他必然提供了文件和目录的一些基本常见操作

按照文件的属性以及相关操作对API进行分类

#### 文件自身属性读取

```
getName()
getParent()
getParentFile()
getPath()
isHidden()
lastModified()
length()
isAbsolute()
isDirectory()
isFile()
exists()
getAbsoluteFile()
getAbsolutePath()
getCanonicalFile()
getCanonicalPath()
getFreeSpace()
getTotalSpace()
getUsableSpace()
```

#### 创建文件/目录基本操作

```
mkdir()
mkdirs()
delete()
deleteOnExit()
renameTo(File)
createTempFile(String, String)
createTempFile(String, String, File)
createNewFile()
```

#### 文件/目录 列表读取

```
listRoots()
list()
list(FilenameFilter)
listFiles()
listFiles(FileFilter)
listFiles(FilenameFilter)
```

#### 文件权限访问以及文件信息设置

```
canExecute()
canRead()
canWrite()

setExecutable(boolean)
setExecutable(boolean, boolean)
setReadable(boolean)
setReadable(boolean, boolean)
setReadOnly()
setWritable(boolean)
setWritable(boolean, boolean)
setLastModified(long)
```

#### 其他

```
toPath()
toString()
toURI()

equals(Object)
compareTo(File)
hashCode()
```

### File API详解

测试:

!(data/attachment/forum/202208/15/151251o2d9dxjxq9ejjn94.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/300 "image.png")

#### File相关的基础信息属性

| 方法                        | 说明                                                                                                                                                                     |
| --------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| ublic String getName()      | 返回由此抽象路径名表示的文件或目录的名称。<br />该名称是路径名名称序列中的最后一个名称。<br />如果路径名名称序列为空,则返回空字符串。<br />测试信息: getName():cccc.txt |
| public String getParent()   | 返回此抽象路径名父目录的路径名字符串;<br />如果此路径名没有指定父目录,则返回 null。<br />getParent():D:\testFile                                                       |
| public File getParentFile() | public String getParent() 的File形式<br />等同于new File(getParent())                                                                                                      |
| public String getPath()   | 将此抽象路径名转换为一个路径名字符串。<br />所得字符串使用默认名称分隔符分隔名称序列中的名称。                                                                         |

一个File用于描述一个抽象路径名

这个抽象路径名(File) 的**名称 name**为:路径名名称序列中的最后一个名称

这个抽象路径名(File) 的**父 parent**为:路径名名称序列中的除了最后一个名称以外的所有

这个抽象路径名(File) 的**路径path**为:路径名名称序列中所有的名称,只不过使用默认的的名称分隔符分割

!(data/attachment/forum/202208/15/151544y4mjn4hq0vc4qmzi.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/300 "image.png")
!(data/attachment/forum/202208/15/151552y2ar6z5zryy1p773.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/300 "image.png")

| 方法                            | 说明                                                                                                                                                                                                                                                                                    |
| ------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| public boolean isHidden()       | **是否隐藏文件** <br />测试此抽象路径名指定的文件是否是一个隐藏文件。<br />隐藏 的具体定义与系统有关                                                                                                                                                                              |
| public long lastModified()      | **long 毫秒数** <br />表示文件最后一次被修改的时间的 long 值,用与时间点(1970 年 1 月 1 日,00:00:00 GMT)之间的毫秒数表示;<br />如果该文件不存在,或者发生 I/O 错误,则返回 0L                                                                                                   |
| public long length()            | **长度,字节** <br />返回由此抽象路径名表示的文件的长度。<br />如果此路径名表示一个目录,则返回值是不确定的。<br />此抽象路径名表示的文件的长度,以字节为单位;<br />如果文件不存在,则返回 0L。<br />对于表示特定于系统的实体(比如设备或管道)的路径名,某些操作系统可能返回 0L。|
| public boolean isAbsolute()   | **是否绝对路径** <br />测试此抽象路径名是否为绝对路径名。<br />绝对路径名的定义与系统有关。<br />在 UNIX 系统上,如果路径名的前缀是 "/",那么该路径名是绝对路径名。<br />在 Microsoft Windows 系统上,如果路径名的前缀是后跟 "\\" 的盘符,或者是 "\\\\",那么该路径名是绝对路径名。 |
| public boolean isDirectory()    | 当且仅当此抽象路径名表示的文件存在且 是一个目录时,返回 true;<br />否则返回 false                                                                                                                                                                                                      |
| public boolean isFile()         | 当且仅当此抽象路径名表示的文件存在且 是一个标准文件时,返回 true;否则返回 false                                                                                                                                                                                                          |
| public boolean exists()         | 当且仅当此抽象路径名表示的文件或目录存在时,返回 true;<br />否则返回 false                                                                                                                                                                                                               |
| public String getAbsolutePath() | 绝对路径名字符串,它与此抽象路径名表示相同的文件或目录                                                                                                                                                                                                                                    |
| public File getAbsoluteFile()   | 绝对    抽象路径名,它与此抽象路径名表示相同的文件或目录相当于new File(this.getAbsolutePath())                                                                                                                                                                                          |

**规范路径名是绝对路径名,并且是惟一的** 。规范路径名的准确定义与系统有关。

如有必要,此方法首先将路径名转换为绝对路径名,这与调用 getAbsolutePath() 方法的效果一样,然后用与系统相关的方式将它映射到其惟一路径名。

这通常涉及到从路径名中移除多余的名称(比如 "." 和 "..")、解析符号连接(对于 UNIX 平台),以及将驱动器号转换为标准大小写形式(对于 Microsoft Windows 平台)。

每个表示现存文件或目录的路径名都有一个惟一的规范形式。

每个表示不存在文件或目录的路径名也有一个惟一的规范形式。

不存在文件或目录路径名的规范形式可能不同于创建文件或目录之后同一路径名的规范形式。

同样,现存文件或目录路径名的规范形式可能不同于删除文件或目录之后同一路径名的规范形式。

| 方法                                                    | 说明                                                       |
| ------------------------------------------------------- | ---------------------------------------------------------- |
| public String getCanonicalPath()    throws IOException| 规范路径名字符串<br />它与此抽象路径名表示相同的文件或目录 |
| public File getCanonicalFile()       throws IOException | 等同于 new File(this.getCanonicalPath())                   |

| 方法                                                                                          | 说明                                                                                                                  |
| --------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------- |
| public long getFreeSpace()<br />public long getTotalSpace()<br />public long getUsableSpace() | 返回此抽象路径名指定的分区中空间相关的数据信息,一定注意是抽象路径名指定的分区未分配 /全部/已使用   空间情况单位是字节数 |

#### File相关的操作

创建 重命名 删除等

| 方法   | 说明                                                                                                                           |
| -------- | ------------------------------------------------------------------------------------------------------------------------------ |
| mkdir()| 创建此抽象路径名指定的目录,当且仅当已创建目录时,返回 true;<br />否则返回 false                                             |
| mkdirs() | 创建此抽象路径名指定的目录,包括所有必需但不存在的父目录。<br />``注意,此操作失败时也可能已经成功地创建了一部分必需的父目录。 |

mkdir/mkdirs用于创建目录
mkdir只会创建最后一个名称为名称的目录,如果一个路径的parent不存在,并不会创建成功
mkdirs 则会创建所有

!(data/attachment/forum/202208/15/152430o55skdsdahabk5a8.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/300 "image.png")

| 方法                                 | 说明                                                                                                                                                                                                                                                                                                   |
| -------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| public<br />boolean renameTo(Filedest) | 重新命名此抽象路径名表示的文件。<br />``参数为File``此方法行为的许多方面都是与平台有关的:<br />重命名操作无法将一个文件从一个文件系统移动到另一个文件系统,该操作不是不可分的<br />如果已经存在具有目标抽象路径名的文件,那么该操作可能无法获得成功。<br />应该始终检查返回值,以确保重命名操作成功。 |

他的参数为File 也是一个抽象路径名 所以说不仅仅就是改一下文件的最后一个名称
他可以把文件进行移动

!(data/attachment/forum/202208/15/152544upst25wfasbsv2sb.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/300 "image.png")

| 方法                     | 说明                                                                                                                                                                                                                                                                                                         |
| -------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| public boolean delete()    | 删除此抽象路径名表示的文件或目录。<br />如果此路径名表示一个目录,则该目录必须为空才能删除。<br />当且仅当成功删除文件或目录时,返回 true;<br />否则返回 false                                                                                                                                              |
| public void deleteOnExit() | 在虚拟机终止时,请求删除此抽象路径名表示的文件或目录。<br />文件(或目录)将以与注册相反的顺序删除。<br />调用此方法删除已注册为删除的文件或目录无效。<br />根据 Java 语言规范中的定义<br />只有在虚拟机正常终止时,才会尝试执行删除操作。<br />一旦请求了删除操作,就无法取消该请求。所以应小心使用此方法。 |

file1 是文件file2是目录,但是目录下还有文件
所以file1删除成功file2删除失败

!(data/attachment/forum/202208/15/152640ourwxtx3uuxnhxh6.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/300 "image.png")

| 方法                                                                                                                                                                                                               | 说明                                                                                                                                                                                                                        |
| -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| public static<br />File createTempFile(<br />String prefix,                                  String suffix,                                  <br />File directory)                         <br /> throws IOException | 在指定目录中创建一个新的空文件,使用给定的前缀和后缀字符串生成其名称。<br />``如果 directory 参数为 null,则使用与系统有关的默认临时文件目录``默认临时文件目录由系统属性 java.io.tmpdir 指定                              |
| public static<br />File createTempFile(<br />String prefix,                                  String suffix)                           throws IOException                                                             | 在默认临时文件目录中创建一个空文件,使用给定前缀和后缀生成其名称。<br />调用此方法等同于调用 createTempFile(prefix, suffix, null)                                                                                           |
| public<br />boolean createNewFile()                      throws IOException                                                                                                                                          | 当且仅当不存在具有此抽象路径名指定名称的文件时,不可分地创建一个新的空文件。<br />``检查文件是否存在,若不存在则创建该文件``<br />如果指定的文件不存在并成功地创建,则返回 true;<br />如果指定的文件已经存在,则返回 false |

#### File相关的列表查询

| 方法                                                | 说明                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                           |
| --------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| public String[] list()                              | 返回一个字符串数组,这些字符串指定此抽象路径名表示的目录中的文件和目录。<br />如果此抽象路径名不表示一个目录,那么此方法将返回 null。<br />否则返回一个字符串数组,每个数组元素对应目录中的每个文件或目录。<br />表示目录本身及其父目录的名称不包括在结果中。<br />每个字符串是一个文件名,而不是一条完整路径。                                                                                                                                                                                                                              |
| public<br />String[] list(FilenameFilter filter)    | 返回一个字符串数组,这些字符串指定此抽象路径名表示的目录中满足指定过滤器的文件和目录。<br />``除了返回数组中的字符串必须满足过滤器外,此方法的行为与 list() 方法相同。``<br />如果给定 filter 为 null,则接受所有名称。                                                                                                                                                                                                                                                                                                                        |
| public File[] listFiles()                           | 返回一个抽象路径名数组,这些路径名表示此抽象路径名表示的目录中的文件。<br />``如果此抽象路径名不表示一个目录,那么此方法将返回 null。``<br />否则返回一个 File 对象数组,每个数组元素对应目录中的每个文件或目录。<br />``表示目录本身及其父目录的名称不包括在结果中。``<br />不保证所得数组中的相同字符串将以特定顺序出现,特别是不保证它们按字母顺序出现。                                                                                                                                                                                    |
| public<br />File[] listFiles(FilenameFilter filter) | 除了返回数组中的路径名必须满足过滤器外,此方法的行为与 listFiles() 方法相同<br />如果给定 filter 为 null,则接受所有路径名                                                                                                                                                                                                                                                                                                                                                                                                                     |
| public<br />File[] listFiles(FileFilter filter)   | 除了返回数组中的路径名必须满足过滤器外,此方法的行为与 listFiles() 方法相同。<br />如果给定 filter 为 null,则接受所有路径名。                                                                                                                                                                                                                                                                                                                                                                                                               |
| public static File[] listRoots()                  | 列出可用的文件系统根。<br />特定 Java 平台可以支持零个或更多个分层组织的文件系统。<br />每个文件系统有一个 root 目录,可以从这里到达文件系统中的所有其他文件。<br />例如,Windows 平台为每个活动驱动器提供了一个根目录;<br />UNIX 平台只有一个根目录,即 "/"。<br />可用文件系统根的设置受各种系统级操作的影响,比如可移动介质的插入和弹出,以及断开或卸载那些物理磁盘或虚拟磁盘。 <br />此方法返回一个 File 对象数组,这些对象表示可用文件系统根的根目录。<br />可以保证本地机器上物理存在的任何文件的规范路径名都以此方法返回的根之一开始。 |

list返回的是名称列表,必须是一个目录
listFile返回的是File列表 必须是一个目录

!(data/attachment/forum/202208/15/152931qydqwcuyluzcq9dc.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/300 "image.png")

!(data/attachment/forum/202208/15/152938s5mv21a5nlj252r0.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/300 "image.png")

ps:直接打印f 调用的是toString形式,返回的是path

**过滤器形式的与无参数版本的行为是相同的,只不过是还要符合过滤器的要求**

对于FilenameFilter和 FileFilter,他们是函数式接口

可以直接使用lambda表达式传入参数

!(data/attachment/forum/202208/15/153002evhzuioikiul0kzq.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/300 "image.png")

对函数式接口不熟悉的可以翻阅之前关于java8的文章

当然你也可以匿名内部类或者实现它,显然lambda表达式是最方便的

下面是调用过程

!(data/attachment/forum/202208/15/153025eq7ssnu6i7090hie.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/300 "image.png")

从上面的调用可以看得出来,
FilenameFilter当前抽象路径名以及所有的名字会传入到方法中
FileFilter则仅仅只有每个抽象路径名

测试FilenameFilter时下面没使用到第一个参数,这个你根据实际情况来

!(data/attachment/forum/202208/15/153044pggmfm3m3083ll0x.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/300 "image.png")

ListRoots

!(data/attachment/forum/202208/15/153056uzbrj7kb2uk4uv4r.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/300 "image.png")

#### File相关权限设置

| 方法                                                      | 说明                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                     |
| ----------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| public boolean canExecute()                                 | 测试应用程序是否可以执行此抽象路径名表示的文件。                                                                                                                                                                                                                                                                                                                                                                                                                                                                                       |
| public boolean canRead()                                    | 测试应用程序是否可以读取此抽象路径名表示的文件。                                                                                                                                                                                                                                                                                                                                                                                                                                                                                       |
| public boolean canRead()                                    | 测试应用程序是否可以修改此抽象路径名表示的文件。                                                                                                                                                                                                                                                                                                                                                                                                                                                                                       |
| setExecutable(boolean)<br />setExecutable(boolean, boolean) | 设置此抽象路径名的所有者或所有用户的执行权限。<br />executable - 如果为 true,则设置允许执行操作的访问权限;<br />如果为 false,则不允许执行操作。<br />ownerOnly - 如果为 true,则执行权限只适用于所有者的执行权限;<br />否则适用于所有用户。<br /> 如果底层文件系统不能区分所有者执行权限与其他执行权限,那么无论该参数为何值,执行权限将适用于所有用户。<br /> 单参数版本是双参数版本的快捷默认设置形式file.setExcutable(arg) 形式的调用与以下调用的行为完全相同:<br />file.setExecutable(arg, true) 也就是单参数默认是设置当前用户 |
| setReadable(boolean)<br />setReadable(boolean, boolean)   | 设置此抽象路径名的所有者或所有用户的读权限。<br />其余的用法形式同setExecutable                                                                                                                                                                                                                                                                                                                                                                                                                                                          |
| setWritable(boolean)<br />setWritable(boolean, boolean)   | 设置此抽象路径名的所有者或所有用户的写权限。<br /> 其余的用法形式同setExecutable                                                                                                                                                                                                                                                                                                                                                                                                                                                         |

setExecutable/setReadable/setWritable 用于设置 执行   读   写 权限

双参数版本第一个参数表示是否允许,第二个参数表示是否是用于所有的用户

一个参数版本是两个参数版本的当前用户的简化快捷形式

| 方法                                    | 说明                                                                                                                                                                                                   |
| ----------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| public boolean setReadOnly()            | 标记此抽象路径名指定的文件或目录,从而只能对其进行读操作。<br />调用此方法后,可以保证在被删除或被标记为允许写访问之前,文件或目录不会发生更改。<br />是否可以删除某个只读文件或目录则取决于底层系统。 |
| public boolean setLastModified(long time) | 设置此抽象路径名指定的文件或目录的最后一次修改时间                                                                                                                                                   |

#### 其他

| 方法                        | 说明                                                                                                         |
| ----------------------------- | ------------------------------------------------------------------------------------------------------------ |
| public<br />Path toPath()   | 返回一个java.nio.file.Path   从这个抽象路径构造的Path对象<br />1.7新增的                                     |
| public<br />String toString() | 返回此抽象路径名的路径名字符串。<br />该字符串就是 getPath() 方法返回的字符串。public String toString() {|

```
return getPath();
```

`<br />`   }                                                      |
| public `<br />`URI toURI()       | 构造一个表示此抽象路径名的 file: URI。该 URI 的具体形式与系统有关。如果可以确定此抽象路径名表示的文件是一个目录,那么所得 URI 将以斜杠结束。 对于某个给定抽象路径名 f,可保证: new File( f.toURI()).equals( f.getAbsoluteFile()) |

| 方法                              | 说明                                                                                                                                                                                                                                                                                                                                                                  |
| ----------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| public int compareTo(File pathname) | 按字母顺序比较两个抽象路径名。<br />此方法定义的顺序取决于底层系统。<br />``在 UNIX 系统上,比较路径名时,字母大小写通常很重要,而在 Microsoft Windows 系统上,这通常不重要。``                                                                                                                                                                                       |
| public boolean equals(Object obj)   | 测试此抽象路径名与给定对象是否相等。<br />``当且仅当该参数不是 null,而是一个与此抽象路径名表示相同的文件或目录的抽象路径名时,返回 true。``<br />两个抽象路径名是否相等取决于底层系统。<br />在 UNIX 系统上,比较路径名时,字母大小写通常很重要,而在 Microsoft Windows 系统上,这通常不重要。                                                                     |
| public int hashCode()               | 计算此抽象路径名的哈希码。<br />``因为抽象路径名的相等性与系统有关,所以对其哈希码的计算也与系统有关。``<br />在 UNIX 系统上,抽象路径名的哈希码等于其路径名字符串和十进制值 1234321 的哈希码的异或。<br />``在 Microsoft Windows 系统上,哈希码等于其转换为小写的路径名字符串和十进制值 1234321 的哈希码的异或。``<br />在将路径名字符串转换为小写时不考虑语言环境。 |

### **FileSystem简介**

File中有一个变量fs类型为FileSystem

compareTo方法依赖于他

而equals方法又依赖compareTo

hashCode也是依赖他

所以说:

compareTo   equals   hashCode   都依赖于 FileSystem fs

!(data/attachment/forum/202208/15/153450js2u26zq6buha2zj.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/300 "image.png")

其实你在回头看看整个File文件中,很多个地方都出现了fs的身影

#### **FileSystem到底是什么?**

操作系统有各自的文件系统,这些文件系统又存在很多差异,而Java 因为是跨平台的,所以它必须要统一处理这些不同平台文件系统之间的差异,才能往上提供统一的入口。

说白了又是接口来实现统一,不同的操作系统实现这个接口,就可以提供统一的表现形式

FileSystem是一个抽象类

!(data/attachment/forum/202208/15/153506goc9p3vsyoi5su2j.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/300 "image.png")

windows下的实现类为:WinNTFileSystem,在IDE中可以直接找到

!(data/attachment/forum/202208/15/153518pecarknrdidyp9ph.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/300 "image.png")

可能你只是找到了一个WinNTFileSystem,只有一个要接口还有什么意思?

如果你目前只看到了一个WinNTFileSystem那说明你在Windows下

WinNTFileSystem类 和 UnixFileSystem类并不是在同一个 JDK 里面,也就是说它们是分开的

你只能在 Windows 版本的 JDK 中找到 WinNTFileSystem,而在 Linux 版本的 JDK 中找到 UnixFileSystem

同样地,其他操作系统也有自己的文件系统实现类。

接下来大致的看下WinNTFileSystem

#### 属性

```java
private final char slash;//斜杠符号
private final char altSlash;//与slash相反的斜杠
private final char semicolon;//分号
private static String[] driveDirCache = new String;//表示驱动盘目录缓存
private ExpiringCache cache = new ExpiringCache();//用于缓存标准路径
private ExpiringCache prefixCache = new ExpiringCache();//用于缓存标准路径前缀
```

其实slash就是名称分隔符
semicolon就是路径分隔符
构造方法中根据系统变量对文件分隔符和路径分隔符进行初始化

!(data/attachment/forum/202208/15/153603yz7tv4jqzty2jav1.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/300 "image.png")

isSlash和 isLetter都非常简单,简单的判断

!(data/attachment/forum/202208/15/153613ldd2yo2kzsfok777.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/300 "image.png")

判断是否以slash开头,是的话直接返回,不是的话,给他加一个

!(data/attachment/forum/202208/15/153624g4l8z0n1i904gi5x.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/300 "image.png")

getSeparator和 getPathSeparator就是File中分隔符的来处

!(data/attachment/forum/202208/15/153634osul56l56xzuszzq.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/300 "image.png")

#### **路径的标准化**

不光标准化,前面还提到了规范化路径 File中有方法getCanonicalFilegetCanonicalPath

他们到底都是在说什么事情呢

先说下标准化,看一个例子

```java
我们给出了一个很奇怪的路径字符串
"D://////\\\\\\/testFile\\\\///////\\wdwqdwqwd.java"
```

!(data/attachment/forum/202208/15/153708wj94wzn3wx9y3cun.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/300 "image.png")

```java
File file = new File("D://////\\\\\\/testFile\\\\///////\\wdwqdwqwd.java");

if (file.exists()){

    System.out.println(file.getName());

}

```

!(data/attachment/forum/202208/15/153740bfgw4q2xgrjrejrq.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/300 "image.png")

虽然看起来很奇怪,但是不影响程序运行
我们此时可以用比较通俗的话来描述这个情况

> 我们给出来了一个乱七八糟的路径,最终路径按照当前文件系统的规则,进行了解析
>
> 去除了不必要的分隔符 或者可能把错误的分隔符进行替换等按照一定的规则,整理出来一个合理的路径
>
> 这就是标准化

debug 看下File的构造方法就知道了
最终他帮我们正确的解析了路径,这就是标准化

!(data/attachment/forum/202208/15/153900ctv5f5xebbvx7aop.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/300 "image.png")

可以看得出来,标准化,借助的仍旧是fs也就是FileSystem

在WinNTFileSystem 中的normalize方法就是标准化路径的一个对外接口
他还有两个相关的private方法,用于处理细节
方法的具体过程,到底是怎么处理的,有兴趣的同学可以继续深挖以下
仔细看下注释也可理解一二
一个标准的win32路径名,不能包括重复的名称分隔符(斜杠) UNC除外 ,也不能以名称分隔符(斜杠)结束
可能是一个空的String
规范化Win32路径名具有便捷的特点:前缀的长度几乎唯一地标识了路径的类型
无论它是绝对的还是相对的
0,1,2,3是分类说明

!(data/attachment/forum/202208/15/153941no3db0o55a8o3636.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/300 "image.png")

如同上面标准化描述的一样,前缀的长度对于标准化很有用,这个方法经常被使用

!(data/attachment/forum/202208/15/153958kzbjj6pbwts100lb.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/300 "image.png")



还是刚才的文件夹列表,这次使用另外的构造方法

!(data/attachment/forum/202208/15/155813oz94rkm48oyt941w.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/300 "image.png")

```java
File file = new File("D:\\\\\\/testFile///////\\\\","\\///wdwqdwqwd.java");

if (file.exists()){

System.out.println(file.getName());

}

```

!(data/attachment/forum/202208/15/155919pcwbh1ppg1h7h1g5.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/300 "image.png")

!(data/attachment/forum/202208/15/155926cjzx6fcn8zebbdxx.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/300 "image.png")

所以可以看得出来resolve做的事情
他要求传递进去的两个字符串都是normal,所以入参传递进去时,就做了处理
虽然说两个都是normal但是两个拼接起来的情况还是很可能需要处理的
比如子路径如果以 slash 开头,丢弃它的头部,所以子路径从第2的位置开始
双参数的resolve就是解决这个问题的

!(data/attachment/forum/202208/15/155950eprjht1rzzshghm3.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/300 "image.png")

一个参数的resolve
public String resolve(File f)
也是类似的道理
只不过他处理的是一个File


1. 获取路径前缀长度
2. 如果头部长为2且以\开头,此时为 UNC 路径,直接返回路径
3. 如果头部长为3,则为本地绝对路径,直接返回路径
4. 如果长度为0,则为相对路径,返回用户路径+此相对路径。
5. 如果长度为1,则为驱动盘相对路径,此时尝试根据用户路径获取驱动盘,存在驱动盘则返回驱动盘+此路径

   不存在驱动盘则说明用户路径是一个 UNC 路径,返回用户路径+此路径。
6. 如果头部长度为2,则为目录相对路径。

   此时先获取用户路径,再根据用户路径获取对应驱动盘,如果路径以驱动盘开头,则直接返回用户路径+去掉驱动盘后的路径。

   如果继续往下则通过 getDriveDirectory 获取指定驱动盘的工作目录,

   将驱动盘+:+工作目录+路径等拼接起来得到最终的新路径,然后还要用安全管理器检查是否有读的权限

!(data/attachment/forum/202208/15/160014befnfph8feph60em.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/300 "image.png")

规范化路径

!(data/attachment/forum/202208/15/160031unzs8kauyahn0z0s.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/300 "image.png")

此处的规范化的含义与File中介绍的返回规范化路径和文件是一致的
看下File中的调用即可,依赖的就是这个方法

!(data/attachment/forum/202208/15/160045ad6rq0mzssm8mdmr.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/300 "image.png")

resolvenormal canonicalize方法本质是一样的,此处说的本质指的是逻辑切入点
他们都是为了处理路径的,只不过是基于不同的场景下去解析组织返回路径
normal最单纯
resolve 用于合并路径,或者将一个File转换为路径
canonicalize 是一个绝对路径,并且是唯一的形式


getUserPath方法   通过 System 获取 user.dir 属性作为用户路径。

getDrive方法         获取驱动盘,先获取路径头部长度,再截取驱动盘。

!(data/attachment/forum/202208/15/160127rjbf3pb6js1689lf.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/300 "image.png")

driveIndex方法
获取驱动盘的索引值,按照字母顺序,比如 a 或 A 则索引值为0

!(data/attachment/forum/202208/15/160141x99lse24lrs0k0r8.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/300 "image.png")


getDriveDirectory方法

获取指定驱动盘下的工作目录,每个驱动盘都有工作目录。

先根据驱动盘获取对应的驱动盘索引

然后尝试从缓存中读取,如果读取得到直接返回

如果获取不到, 使用本地方法获取,然后在缓存起来

!(data/attachment/forum/202208/15/160152wwoj8pswrlmj2pt2.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/300 "image.png")

fromURIPath主要是完成了路径的格式化
看代码的注释,注释就是示例程序

!(data/attachment/forum/202208/15/160208z1nnncsu4lsb97b3.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/300 "image.png")

WinNTFileSystem还有不少方法,其中有些还是本地方法,只需要大致了解功能即可
不是public的外面也用不了

!(data/attachment/forum/202208/15/160226oceo6oz1buwq2uau.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/300 "image.png")


不过这个类对于了解File 的基本实现是很有帮助的

因为可以说File非常非常的依赖他

UnixFileSystem的逻辑概念也是类似的,算是废话了,毕竟都是实现同一个接口

本文主要对java中   抽象路径名File这一概念进行了详细的解读

并且介绍了File 依赖的底层接口FileSystem文件系统

不同的操作系统有不同的文件系统,FileSystem 接口用于提供一致性的操作访问

不同的操作系统提供不同的实现类

操作文件依赖底层操作系统,所以File 也必然依赖底层系统

关于文件系统中的规范化标准化可能会有一定的疑惑,因为

其实你跳出来代码的思维来看,就是说window平台对于文件路径名称格式本身就有一些的要求

所谓标准化就是适配这种格式,就好像学生时代让穿校服一样,那你到了这个学校就换上这个学校的校服,没什么好奇怪的

你给出来的一个路径,想要在某个环境下运行,这个路径必须是跟本地系统适配的



#### **关于路径相关的一些补充**

根据上面的介绍,很显然,名称分隔符和路径分隔符,不同平台下是不同的

File中的分隔符都是获取的本地系统的

所以不要在你的代码中写死某种分隔符,而是使用File给我们提供的哪几个public static final定义的分隔符

下面说下windows下的一些路径概念



| 路径的一些补充说明                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                         |
| ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| 绝对路径是一个广泛的概念,它表示的是可以唯一定位一个文件或文件夹的路径,有多种形式的路径都属于绝对路径的范畴<br />比如,完整路径(Full path)我们平时所说的“绝对路径”通常就是指完整路径<br />它的windows格式如下:C:\Windows\System32\drivers\etc\hosts                                                                                                                                                                                                                                                                                                                                                                     |
| UNC是网络(主要指局域网)中用于标志共享文件的路径<br />在windows下格式\\servername\sharename\path\filename<br />包括计算机名/共享文件夹名/以及共享文件夹下的路径                                                                                                                                                                                                                                                                                                                                                                                                                                                               |
| 相对路径都是以某一个路径为基础的                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                             |
| 纯粹的相对路径<br />纯粹的相对路径格式如下:Windows\System32\calc.exe 可以看得到没有 斜杆<br />也没有盘符<br />相对的位置是进程的当前文件夹进程的当前文件夹<br />并不是指EXE执行文件所在的文件夹<br />比如cmd控制台cmd.exe<br />程序的位置不会变,但是你可以切换当前文件夹的位置,切换过的位置就是当前文件夹                                                                                                                                                                                                                                                                                                               |
| 斜杠 开头的相对路径<br /> ``斜杠开头的表示相对于当前文件夹的根路径,根据上面介绍的当前文件夹,然后确定他的根路径``<br />比如当前是C:\Windows根就是C   相对的就是C                                                                                                                                                                                                                                                                                                                                                                                                                                                            |
| 盘符开头的相对路径<br /> ``C:System32\calc.exe 看起来跟完整路径类似,但是冒号:后面却没有斜杠``这也是一种相对路径<br /> ``表示的是进程在该分区上的当前文件夹``<br />进程会保留在每个分区上的当前文件夹<br />比如你从 C盘 跳到了D盘,你的当前文件夹变化了<br />但是你在C盘最后一次的当前文件夹不在变动了,这就是分区上的当前文件夹<br />!(data/attachment/forum/202208/15/160631iphquc2lz664zvp7.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/300 "image.png")<br />calc计算器位于上面的路径,打开文件可以执行<br />切换到别的分区,当你再次切换到C盘的时候,直接就回到了上一次的文件路径,这就是分区的当前文件夹 |


linux的绝对路径是指从根目录说起的. 例如 /home/somedir/..
而相对路径则是从当前目录说起: 即 ./

有4个相对路径的表示方法:
当前目录 .
父目录 ..
某用户的根目录 ~user
自己的根目录 ~

!(data/attachment/forum/202206/16/141330jha7st9soow8772i.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/300 "common_log.png")
`转载务必注明出处:程序员潇然,疯狂的字节X,https://crazybytex.com/thread-130-1-1.html `
页: [1]
查看完整版本: JavaIO之File详解 以及FileSystem WinNTFileSystem简介(三)