File类
文件和目录路径名的抽象表示形式。
我们知道,对于不同的操作系统,文件路径的描述是不同的
比如
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 也可以用来生成文件
new File只是在java中描述这么一个文件,是否真的存在? 你还需要进行去验证,只是一个虚拟的描述符
File file = new File("D:\\testFile");//file就是对这个路径的一个描述,那么是否真的存在? 你还需要进行去验证 |
名称与路径的分隔符
另外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详解
测试:
File相关的基础信息属性
public String getName() | 返回由此抽象路径名表示的文件或目录的名称。 该名称是路径名名称序列中的最后一个名称。如果路径名名称序列为空,则返回空字符串。 测试信息: getName(): cccc.txt |
public String getParent() | 返回此抽象路径名父目录的路径名字符串; 如果此路径名没有指定父目录,则返回 null。 getParent(): D:\testFile |
public File getParentFile() | public String getParent() 的File形式,等同于new File(getParent()) |
public String getPath() | 将此抽象路径名转换为一个路径名字符串。 所得字符串使用 默认名称分隔符 分隔名称序列中的名称。 |
一个File用于描述一个抽象路径名
这个抽象路径名(File) 的名称 name为 路径名名称序列中的最后一个名称
public boolean isHidden() | 是否隐藏文件 测试此抽象路径名指定的文件是否是一个隐藏文件。 隐藏 的具体定义与系统有关 |
public long lastModified()
|
long 毫秒数 表示文件最后一次被修改的时间的 long 值, 用与时间点(1970 年 1 月 1 日,00:00:00 GMT)之间的毫秒数表示; 如果该文件不存在,或者发生 I/O 错误,则返回 0L |
public long length() | 长度,字节 返回由此抽象路径名表示的文件的长度。 如果此路径名表示一个目录,则返回值是不确定的。
此抽象路径名表示的文件的长度,以字节为单位;
如果文件不存在,则返回 0L。
对于表示特定于系统的实体(比如设备或管道)的路径名,某些操作系统可能返回 0L。
|
public boolean isAbsolute() |
是否绝对路径
测试此抽象路径名是否为绝对路径名。绝对路径名的定义与系统有关。
在 UNIX 系统上,如果路径名的前缀是 "/",那么该路径名是绝对路径名。
在 Microsoft Windows 系统上,
如果路径名的前缀是后跟 "\\" 的盘符,或者是 "\\\\",那么该路径名是绝对路径名。
|
public boolean isDirectory() | 当且仅当此抽象路径名表示的文件存在且 是一个目录时,返回 true;否则返回 false |
public boolean isFile() | 当且仅当此抽象路径名表示的文件存在且 是一个标准文件时,返回 true;否则返回 false |
public boolean exists() | 当且仅当此抽象路径名表示的文件或目录存在时,返回 true;否则返回 false |
public String getAbsolutePath() | 绝对路径名字符串,它与此抽象路径名表示相同的文件或目录 |
public File getAbsoluteFile()
|
绝对 抽象路径名,它与此抽象路径名表示相同的文件或目录 相当于new File(this.getAbsolutePath())
|
规范路径名是绝对路径名,并且是惟一的。规范路径名的准确定义与系统有关。
如有必要,此方法首先将路径名转换为绝对路径名,这与调用 getAbsolutePath() 方法的效果一样,然后用与系统相关的方式将它映射到其惟一路径名。
这通常涉及到从路径名中移除多余的名称(比如 "." 和 "..")、解析符号连接(对于 UNIX 平台),以及将驱动器号转换为标准大小写形式(对于 Microsoft Windows 平台)。
每个表示现存文件或目录的路径名都有一个惟一的规范形式。
每个表示不存在文件或目录的路径名也有一个惟一的规范形式。
不存在文件或目录路径名的规范形式可能不同于创建文件或目录之后同一路径名的规范形式。
同样,现存文件或目录路径名的规范形式可能不同于删除文件或目录之后同一路径名的规范形式。
public String getCanonicalPath()
throws IOException
|
规范路径名字符串,它与此抽象路径名表示相同的文件或目录
|
public File getCanonicalFile()
throws IOException
|
等同于 new File(this.getCanonicalPath()) |
public long getFreeSpace()
public long getTotalSpace()
public long getUsableSpace()
|
返回此抽象路径名指定的分区中空间相关的数据信息,一定注意是抽象路径名指定的分区 未分配 /全部/已使用 空间情况 单位是字节数 |
File相关的操作
创建 重命名 删除等
mkdir()
|
创建此抽象路径名指定的目录,当且仅当已创建目录时,返回 true;否则返回 false |
mkdirs() | 创建此抽象路径名指定的目录,包括所有必需但不存在的父目录。 注意,此操作失败时也可能已经成功地创建了一部分必需的父目录。 |
mkdir/mkdirs 用于创建目录
mkdir只会创建最后一个名称为名称的目录, 如果一个路径的parent不存在,并不会创建成功
mkdirs 则会创建所有
public boolean renameTo(File dest) | 重新命名此抽象路径名表示的文件。 参数为File
此方法行为的许多方面都是与平台有关的:重命名操作无法将一个文件从一个文件系统移动到另一个文件系统,
该操作不是不可分的,如果已经存在具有目标抽象路径名的文件,那么该操作可能无法获得成功。
应该始终检查返回值,以确保重命名操作成功。
|
他的参数为File 也是一个抽象路径名 所以说不仅仅就是改一下文件的最后一个名称
他可以把文件进行移动
public boolean delete() | 删除此抽象路径名表示的文件或目录。如果此路径名表示一个目录,则该目录必须为空才能删除。
当且仅当成功删除文件或目录时,返回 true;否则返回 false
|
public void deleteOnExit() |
在虚拟机终止时,请求删除此抽象路径名表示的文件或目录。
文件(或目录)将以与注册相反的顺序删除。
调用此方法删除已注册为删除的文件或目录无效。
根据 Java 语言规范中的定义,只有在虚拟机正常终止时,才会尝试执行删除操作。
一旦请求了删除操作,就无法取消该请求。所以应小心使用此方法。
|
file1 是文件 file2是目录,但是目录下还有文件
所以file1删除成功 file2删除失败
public static File createTempFile(String prefix,
String suffix,
File directory)
throws IOException
|
在指定目录中创建一个新的空文件,使用给定的前缀和后缀字符串生成其名称。 如果 directory 参数为 null,则使用与系统有关的默认临时文件目录 默认临时文件目录由系统属性 java.io.tmpdir 指定 |
public static File createTempFile(String prefix,
String suffix)
throws IOException
|
在默认临时文件目录中创建一个空文件,使用给定前缀和后缀生成其名称。 调用此方法等同于调用 createTempFile(prefix, suffix, null) |
public boolean createNewFile()
throws IOException
|
当且仅当不存在具有此抽象路径名指定名称的文件时,不可分地创建一个新的空文件。 检查文件是否存在,若不存在则创建该文件 如果指定的文件不存在并成功地创建,则返回 true;如果指定的文件已经存在,则返回 false |
File相关的列表查询
public String[] list() | 返回一个字符串数组,这些字符串指定此抽象路径名表示的目录中的文件和目录。
如果此抽象路径名不表示一个目录,那么此方法将返回 null。
否则返回一个字符串数组,每个数组元素对应目录中的每个文件或目录。
表示目录本身及其父目录的名称不包括在结果中。每个字符串是一个文件名,而不是一条完整路径。
|
public String[] list(FilenameFilter filter) | 返回一个字符串数组,这些字符串指定此抽象路径名表示的目录中满足指定过滤器的文件和目录。 除了返回数组中的字符串必须满足过滤器外,此方法的行为与 list() 方法相同。 如果给定 filter 为 null,则接受所有名称。 |
public File[] listFiles() | 返回一个抽象路径名数组,这些路径名表示此抽象路径名表示的目录中的文件。 如果此抽象路径名不表示一个目录,那么此方法将返回 null。 否则返回一个 File 对象数组,每个数组元素对应目录中的每个文件或目录。 表示目录本身及其父目录的名称不包括在结果中。 不保证所得数组中的相同字符串将以特定顺序出现,特别是不保证它们按字母顺序出现。 |
public File[] listFiles(FilenameFilter filter) | 除了返回数组中的路径名必须满足过滤器外,此方法的行为与 listFiles() 方法相同 如果给定 filter 为 null,则接受所有路径名 |
public File[] listFiles(FileFilter filter) | 除了返回数组中的路径名必须满足过滤器外,此方法的行为与 listFiles() 方法相同。 如果给定 filter 为 null,则接受所有路径名。 |
public static File[] listRoots() |
列出可用的文件系统根。
特定 Java 平台可以支持零个或更多个分层组织的文件系统。
每个文件系统有一个 root 目录,可以从这里到达文件系统中的所有其他文件。
例如,Windows 平台为每个活动驱动器提供了一个根目录;
UNIX 平台只有一个根目录,即 "/"。
可用文件系统根的设置受各种系统级操作的影响,比如可移动介质的插入和弹出,以及断开或卸载那些物理磁盘或虚拟磁盘。
此方法返回一个 File 对象数组,这些对象表示可用文件系统根的根目录。
可以保证本地机器上物理存在的任何文件的规范路径名都以此方法返回的根之一开始。
|
list返回的是名称列表 ,必须是一个目录
listFile返回的是File列表 必须是一个目录
ps:直接打印f 调用的是toString 形式,返回的是path
过滤器形式的与无参数版本的行为是相同的,只不过是还要符合过滤器的要求
对于FilenameFilter 和 FileFilter,他们是函数式接口
可以直接使用lambda表达式传入参数
File相关权限设置
public boolean canExecute() | 测试应用程序是否可以执行此抽象路径名表示的文件。 |
public boolean canRead() | 测试应用程序是否可以读取此抽象路径名表示的文件。 |
public boolean canRead() | 测试应用程序是否可以修改此抽象路径名表示的文件。 |
setExecutable(boolean)
setExecutable(boolean, boolean)
|
设置此抽象路径名的所有者或所有用户的执行权限。
executable - 如果为 true,则设置允许执行操作的访问权限;如果为 false,则不允许执行操作。
ownerOnly - 如果为 true,则执行权限只适用于所有者的执行权限;否则适用于所有用户。
如果底层文件系统不能区分所有者执行权限与其他执行权限,那么无论该参数为何值,执行权限将适用于所有用户。
单参数版本是双参数版本的快捷默认设置形式
file.setExcutable(arg) 形式的调用与以下调用的行为完全相同:file.setExecutable(arg, true)
也就是单参数默认是设置当前用户
|
setReadable(boolean)
setReadable(boolean, boolean)
|
设置此抽象路径名的所有者或所有用户的读权限。 其余的用法形式同setExecutable |
setWritable(boolean)
setWritable(boolean, boolean)
|
设置此抽象路径名的所有者或所有用户的写权限。
其余的用法形式同setExecutable
|
setExecutable/setReadable/setWritable 用于设置 执行 读 写 权限
双参数版本 第一个参数表示是否允许,第二个参数表示是否是用于所有的用户
一个参数版本是两个参数版本的当前用户的简化快捷形式
public boolean setReadOnly() |
标记此抽象路径名指定的文件或目录,从而只能对其进行读操作。
调用此方法后,可以保证在被删除或被标记为允许写访问之前,文件或目录不会发生更改。
是否可以删除某个只读文件或目录则取决于底层系统。
|
public boolean setLastModified(long time) | 设置此抽象路径名指定的文件或目录的最后一次修改时间。 |
其他
public Path toPath() | 返回一个java.nio.file.Path 从这个抽象路径构造的Path对象 1.7新增的 |
public String toString() | 返回此抽象路径名的路径名字符串。该字符串就是 getPath() 方法返回的字符串。
public String toString() {
return getPath();
}
|
public URI toURI() |
构造一个表示此抽象路径名的 file: URI。
该 URI 的具体形式与系统有关。如果可以确定此抽象路径名表示的文件是一个目录,那么所得 URI 将以斜杠结束。
对于某个给定抽象路径名 f,可保证:
new File( f.toURI()).equals( f.getAbsoluteFile())
|
public int compareTo(File pathname) | 按字母顺序比较两个抽象路径名。此方法定义的顺序取决于底层系统。 在 UNIX 系统上,比较路径名时,字母大小写通常很重要,而在 Microsoft Windows 系统上,这通常不重要。 依赖 |
public boolean equals(Object obj) | 测试此抽象路径名与给定对象是否相等。 当且仅当该参数不是 null,而是一个与此抽象路径名表示相同的文件或目录的抽象路径名时,返回 true。 两个抽象路径名是否相等取决于底层系统。 在 UNIX 系统上,比较路径名时,字母大小写通常很重要,而在 Microsoft Windows 系统上,这通常不重要。 |
public int hashCode() | 计算此抽象路径名的哈希码。 因为抽象路径名的相等性与系统有关,所以对其哈希码的计算也与系统有关。 在 UNIX 系统上,抽象路径名的哈希码等于其路径名字符串和十进制值 1234321 的哈希码的异或。 在 Microsoft Windows 系统上,哈希码等于其转换为小写的路径名字符串和十进制值 1234321 的哈希码的异或。 在将路径名字符串转换为小写时不考虑语言环境。 |
FileSystem简介
File中有一个变量fs 类型为FileSystem
compareTo方法依赖于他
而equals方法又依赖compareTo
hashCode也是依赖他
所以说:
compareTo equals hashCode 都依赖于 FileSystem fs
其实你在回头看看整个File文件中,很多个地方都出现了fs的身影
FileSystem到底是什么?
操作系统有各自的文件系统,这些文件系统又存在很多差异,而Java 因为是跨平台的,所以它必须要统一处理这些不同平台文件系统之间的差异,才能往上提供统一的入口。
说白了又是接口来实现统一,不同的操作系统实现这个接口,就可以提供统一的表现形式
FileSystem是一个抽象类
windows下的实现类为:WinNTFileSystem,在IDE中可以直接找到
可能你只是找到了一个WinNTFileSystem,只有一个要接口还有什么意思?
如果你目前只看到了一个WinNTFileSystem 那说明你在Windows下
WinNTFileSystem类 和 UnixFileSystem类并不是在同一个 JDK 里面,也就是说它们是分开的
你只能在 Windows 版本的 JDK 中找到 WinNTFileSystem,而在 Linux 版本的 JDK 中找到 UnixFileSystem
同样地,其他操作系统也有自己的文件系统实现类。
接下来大致的看下WinNTFileSystem
属性
private final char slash;//斜杠符号 private final char altSlash;//与slash相反的斜杠 private final char semicolon;//分号 private static String[] driveDirCache = new String[26];//表示驱动盘目录缓存 private ExpiringCache cache = new ExpiringCache();//用于缓存标准路径 private ExpiringCache prefixCache = new ExpiringCache();//用于缓存标准路径前缀
其实slash就是名称分隔符
semicolon就是路径分隔符
构造方法中根据系统变量对文件分隔符和路径分隔符进行初始化
isSlash 和 isLetter都非常简单,简单的判断
判断是否以slash 开头,是的话直接返回,不是的话,给他加一个
getSeparator 和 getPathSeparator 就是File中分隔符的来处
路径的标准化
不光标准化,前面还提到了规范化路径 File中有方法getCanonicalFile getCanonicalPath
他们到底都是在说什么事情呢
先说下标准化,看一个例子
虽然看起来很奇怪,但是不影响程序运行
我们此时可以用比较通俗的话来描述这个情况
我们给出来了一个乱七八糟的路径,最终路径按照当前文件系统的规则,进行了解析,
去除了不必要的分隔符 或者可能把错误的分隔符进行替换等按照一定的规则
整理出来一个合理的路径,这就是标准化
|
debug 看下File的构造方法 就知道了
最终他帮我们正确的解析了路径,这就是标准化
可以看得出来,标准化,借助的仍旧是fs 也就是FileSystem
在WinNTFileSystem 中的normalize方法就是标准化路径的一个对外接口
他还有两个相关的private方法,用于处理细节
方法的具体过程,到底是怎么处理的,有兴趣的同学可以继续深挖以下
仔细看下注释也可理解一二
一个标准的win32路径名,不能包括重复的名称分隔符(斜杠) UNC除外 ,也不能以名称分隔符(斜杠)结束
可能是一个空的String
规范化Win32路径名具有便捷的特点:前缀的长度几乎唯一地标识了路径的类型
无论它是绝对的还是相对的
0,1,2,3是分类说明
如同上面标准化描述的一样,前缀的长度对于标准化很有用,这个方法经常被使用
还是刚才的文件夹列表 这次使用另外的构造方法
File file = new File("D:\\\\\\/testFile///////\\\\","\\///wdwqdwqwd.java"); if (file.exists()){ System.out.println(file.getName()); }
所以可以看得出来resolve做的事情
他要求传递进去的两个字符串都是normal的,所以入参传递进去时,就做了处理
虽然说两个都是normal但是两个拼接起来的情况还是很可能需要处理的,
比如子路径如果以 slash 开头,丢弃它的头部,所以子路径从第2的位置开始
双参数的resolve就是解决这个问题的
一个参数的resolve
public String resolve(File f)
也是类似的道理
只不过他处理的是一个File
|
规范化路径
此处的规范化的含义与File中介绍的返回规范化路径和文件是一致的
看下File中的调用即可,依赖的就是这个方法
resolve normal canonicalize方法本质是一样的,此处说的本质指的是逻辑切入点
他们都是为了处理路径的,只不过是基于不同的场景下去解析组织返回路径
normal最单纯
resolve 用于合并路径,或者将一个File转换为路径
canonicalize 是一个绝对路径,并且是唯一的形式
WinNTFileSystem 还有不少方法,其中有些还是本地方法,只需要大致了解功能即可
不是public的外面也用不了
不过这个类对于了解File 的基本实现是很有帮助的
因为可以说File非常非常的依赖他
UnixFileSystem的逻辑概念也是类似的,算是废话了,毕竟都是实现同一个接口
本文主要对java中 抽象路径名 File这一概念进行了详细的解读
并且介绍了File 依赖的底层接口 FileSystem 文件系统
不同的操作系统有不同的文件系统,FileSystem 接口用于提供一致性的操作访问
不同的操作系统提供不同的实现类
操作文件依赖底层操作系统,所以File 也必然依赖底层系统
关于文件系统中的规范化标准化可能会有一定的疑惑,因为
其实你跳出来代码的思维来看,就是说window平台对于文件路径名称格式本身就有一些的要求
所谓标准化就是适配这种格式,就好像学生时代让穿校服一样,那你到了这个学校就换上这个学校的校服,没什么好奇怪的
你给出来的一个路径,想要在某个环境下运行,这个路径必须是跟本地系统适配的
关于路径相关的一些补充
根据上面的介绍,很显然,名称分隔符和路径分隔符,不同平台下是不同的
File中的分隔符都是获取的本地系统的
所以不要在你的代码中写死某种分隔符,而是使用File给我们提供的哪几个public static final定义的分隔符
下面说下windows下的一些路径概念
linux的绝对路径是指从根目录说起的. 例如 /home/somedir/..
而相对路径则是从当前目录说起: 即 ./
|
有4个相对路径的表示方法:
当前目录 .
父目录 ..
某用户的根目录 ~user
自己的根目录 ~
|