likes
comments
collection
share

Java 中的 File 类

作者站长头像
站长
· 阅读数 15

我正在参加「掘金·启航计划」

这是 android 文件操作的第一篇,之所以从 Java 开始,是因为这样能从前到后彻底弄明白文件相关的操作。

环境说明:

  • 我学习以 JDK8 为主,之所以选择 8 ,是因为只有 8 有教程,估计 File 相关的 API ,从 8 到 18 都是没有变的,先找到 File 相关的 API;
  • 我的示例都是跑在 JDK18 基础上;
  • 运行环境是 MacOS 13.3.1 (a) (22E772610a);
  • 编辑器为: IntelliJ IDEA 2023.1.2 (Community Edition) ;
  • 写于 2023-6-11 。

其他说明:

  • 文件夹和目录同一个含义;
  • Path 和路径同一含义。
  1. 类 API

展示所有 File 类相关的方法和属性,也就是文档中给出,具体查看文档: JDK File 。翻译是使用谷歌翻译的结果,读得懂英语的直接看英文,读不懂的看我的理解;翻译只是辅助,那些看得懂英语,但又不是完全看得懂的人参考。

1.1 属性

属性名称类/对象属性官方描述和翻译我的理解
pathSeparatorstaticThe system-dependent path-separator character, represented as a string for convenience.为方便起见,表示为字符串的系统相关路径分隔符路径与路径之间的分隔符,比如两个文件路径:/usr/local/mongodb/bin:/usr/local/mysql/bin。在 Unix 中是 “ : ”,在 Window 中则是 “ ; ”。
pathSeparatorCharstaticThe system-dependent path-separator character.依赖于系统的路径分隔符跟上面的同一个含义,只是上面的返回 String ,这个返回的是 Char 。
separatorstaticThe system-dependent default name-separator character, represented as a string for convenience.为方便起见,系统相关的默认名称分隔符表示为字符串路径中的分隔符,比如 /usr/local/mongodb/bin 中的 / 就是 separator 。在 Unix 中是 / ,在 Window 中则是 `` 。
separatorCharstaticThe system-dependent default name-separator character.系统相关的默认名称分隔符跟上面相同的含义,上面返回的是 String ,这个返回 Char

1.2 构造函数

构造函数官方描述和翻译我的理解
File(File parent, String child)Creates a new File instance from a parent abstract pathname and a child pathname string.从父抽象路径名和子路径名字符串创建新文件实例。拿着第一个参数的 path 与第二个参数组合成一个新的 path ;如果第一个参数传入为 null ,那么就跟**File(String** pathname) 构造函数相同。
File(String pathname)Creates a new File instance by converting the given pathname string into an abstract pathname.通过将给定的路径名字符串转换为抽象路径名来创建一个新的文件实例。使用参数构建一个文件对象,本身只是保存 path 参数,其他不做任何操作,包括对参数的有效性校验也没有;但是不能传入 null ,会直接抛出空指针异常。
File(String parent, String child)Creates a new File instance from a parent pathname string and a child pathname string.从父路径名字符串和子路径名字符串创建新文件实例。同第一个构造函数,差别在于第一个构造函数需要取 File 对象下的 path 属性,而这个直接使用;同样传入为 null 的话就跟第二个构造函数一样。
File(URI uri)Creates a new File instance by converting the given file: URI into an abstract pathname.通过将给定文件 uri 转换为抽象路径名来创建新文件实例。跟第二个构造函数差不多含义,区别在于这个需要取出 URI 对象中的相关属性。

1.3 方法

方法声明官方描述和翻译我的理解
boolean canExecute()Tests whether the application can execute the file denoted by this abstract pathname.测试应用程序是否可以执行此抽象路径名表示的文件。返回当前路径中的文件是否为可执行文件。当这个文件、文件夹本身还不存在,直接返回 false ;文件属性,如果有可执行权限并有权限的情况下,返回 true ,否则返回false ;本身不管执行结果是否真的可靠。
boolean canRead()Tests whether the application can read the file denoted by this abstract pathname.测试应用程序是否可以读取此抽象路径名表示的文件。判断文件是否有可读权限,其余同上。
boolean canWrite()Tests whether the application can modify the file denoted by this abstract pathname.测试应用程序是否可以修改此抽象路径名表示的文件。判断文件是否有可写权限,其余同上。
int compareTo(File pathname)Compares two abstract pathnames lexicographically.按字典顺序比较两个抽象路径名。StringcompareTo 相似,具体看下面的示例。
boolean createNewFile()Atomically creates a new, empty file named by this abstract pathname if and only if a file with this name does not yet exist.当且仅当具有此名称的文件尚不存在时,以原子方式创建一个以此抽象路径名命名的新空文件。创建新文件,创建的文件原本不存在,所创建文件的所属文件夹存在并且有权限才能成功。
static File ****createTempFile(String prefix,String suffix)Creates an empty file in the default temporary-file directory, using the given prefix and suffix to generate its name.使用给定的前缀和后缀在默认临时文件目录中创建一个空文件以生成其名称。创建包含指定文件前缀和后缀的临时文件。
static File ****createTempFile(String prefix,String suffix,File directory)Creates a new empty file in the specified directory, using the given prefix and suffix strings to generate its name.使用给定的前缀和后缀字符串在指定目录中创建一个新的空文件以生成其名称。在给出的文件夹中创建包含指定文件前缀和后缀的文件。详情见 2.3.26
boolean delete()Deletes the file or directory denoted by this abstract pathname.删除此抽象路径名表示的文件或目录。删除文件或文件夹。需要文件或文件夹的所属文件夹有权限。
void deleteOnExit()Requests that the file or directory denoted by this abstract pathname be deleted when the virtual machine terminates.请求在虚拟机终止时删除此抽象路径名表示的文件或目录。删除文件或文件夹,跟 delete 相同,只不过这个是在虚拟机终止才会去删除,而不是立马删除。
boolean equals(Object obj)Tests this abstract pathname for equality with the given object.测试此抽象路径名是否与给定对象相等。参数如果不是 File 对象直接返回 false ,否则跟 int compareTo(File pathname) 相同。
boolean exists()Tests whether the file or directory denoted by this abstract pathname exists.测试此抽象路径名表示的文件或目录是否存在。判断文件或文件夹是否存在。
File ****getAbsoluteFile()Returns the absolute form of this abstract pathname.返回此抽象路径名的绝对形式。得到绝对路径的 File 对象,就是拿 File 对象的绝对路径来新建一个新的 File 对象。详情见 2.3.15
String ****getAbsolutePath()Returns the absolute pathname string of this abstract pathname.返回此抽象路径名的绝对路径名字符串。获取 File 的绝对路径,如果本身就是直接返回。
File ****getCanonicalFile()Returns the canonical form of this abstract pathname.返回此抽象路径名的规范形式。用文件的规范路径创建新的 File 对象,至于什么是规范路径看 String ****getCanonicalPath() 函数;这里的规范是我使用翻译软件得到的结果,但含义是没问题的。
String ****getCanonicalPath()Returns the canonical pathname string of this abstract pathname.返回此抽象路径名的规范路径名字符串。获取规范路径,也就是如果文件/文件夹里面带有 ... 这样的存在,那么这些会整合到路径中,显示真正的路径;如果 File 对象的 path 是一个软链接,那么会显示文件真正的路径。 详情见 2.3.16
long getFreeSpace()Returns the number of unallocated bytes in the partition named by this abstract path name.返回由此抽象路径名命名的分区中未分配的字节数。我没有弄懂,网上的含义是:方法返回此抽象路径名的分区中的未分配的字节数。 分配的字节数返回的不是一个保证。 未分配的字节数可能是这个调用和不准确的任何外部I/ O操作后立即是准确的。信息来源于:getFreeSpace
String ****getName()Returns the name of the file or directory denoted by this abstract pathname.返回此抽象路径名表示的文件或目录的名称。获取路径中的最后一个名称,假如:test/a/b/c ,那么得到的是 c ;如果是 ../ ,那么得到的是 .. 。详情看 2.3.14
String ****getParent()Returns the pathname string of this abstract pathname's parent, or null if this pathname does not name a parent directory.返回此抽象路径名父目录的路径名字符串,如果此路径名未指定父目录,则返回 null 。返回当前文件或文件夹的父级文件夹。主要是看 path 中是否含有 / ,如果有,去掉最后一个 / 后的内容就是父级文件路径。跟创建文件时的 pathname 有直接关系,如果是相对路径也只会返回相对路径。
File ****getParentFile()Returns the abstract pathname of this abstract pathname's parent, or null if this pathname does not name a parent directory.返回此抽象路径名父目录的抽象路径名;如果此路径名未指定父目录,则返回 null 。跟上一个相似,只不过这个会创建 File 对象。
String ****getPath()Converts this abstract pathname into a pathname string.将此抽象路径名转换为路径名字符串。获取 Filepath ,就是创建对象时传入的参数,具体看 2.3.12 示例。
long getTotalSpace()Returns the size of the partition named by this abstract pathname.返回由此抽象路径名命名的分区的大小。不是很明白,也不知道有啥用,网上的解释:返回此抽象路径名的分区的大小。信息来源于:getTotalSpace
long getUsableSpace()Returns the number of bytes available to this virtual machine on the partition named by this abstract pathname.返回此抽象路径名命名的分区上此虚拟机可用的字节数。同上。网上的解释:返回可用字节数,这个虚拟机上的分区是此抽象名字。这种方法通常会提供多少新的数据实际上可以写成这种方法检查写权限和其他操作系统的限制,以更准确的估计。信息来源于: getUsableSpace
int hashCode()Computes a hash code for this abstract pathname.计算此抽象路径名的哈希码。也就是 hashcode 值。至于为啥需要用到这个,因为 java 中都是有这个的,所以以后会出相关得到学习记录。
boolean isAbsolute()Tests whether this abstract pathname is absolute.测试这个抽象路径名是否是绝对的。File 对象的 path 是否为绝对路径。也就是返回 File 对象初始化的时候是否是绝对路径。
boolean isDirectory()Tests whether the file denoted by this abstract pathname is a directory.测试此抽象路径名表示的文件是否为目录。判断 path 是不是文件夹。
boolean isFile()Tests whether the file denoted by this abstract pathname is a normal file.测试此抽象路径名表示的文件是否为普通文件。判断 path 是不是文件。
boolean isHidden()Tests whether the file named by this abstract pathname is a hidden file.测试以此抽象路径名命名的文件是否为隐藏文件。判断路径是不是处于隐藏的状态。也就是在访达中看不到的文件或文件夹。
long lastModified()Returns the time that the file denoted by this abstract pathname was last modified.返回最后修改此抽象路径名表示的文件的时间。返回文件或文件夹最近一次修改的时间,如果文件或文件夹不存在那么返回 0
long length()Returns the length of the file denoted by this abstract pathname.返回此抽象路径名表示的文件的长度。如果是文件返回文件中的内容长度(字节),文件夹返回的值未指定,详情见: 2.3.32
String [] list()Returns an array of strings naming the files and directories in the directory denoted by this abstract pathname.返回一个字符串数组,命名此抽象路径名表示的目录中的文件和目录。返回文件夹中的文件或文件夹。
String [] list(FilenameFilter filter)Returns an array of strings naming the files and directories in the directory denoted by this abstract pathname that satisfy the specified filter.返回一个字符串数组,命名此抽象路径名表示的目录中满足指定过滤器的文件和目录。按指定过滤器过滤后的文件或文件夹。
File [] listFiles()Returns an array of abstract pathnames denoting the files in the directory denoted by this abstract pathname.返回抽象路径名数组,表示此抽象路径名表示的目录中的文件。String [] list() 相似,不同在于这个会返回 File 对象的数组。
File [] listFiles(FileFilter filter)Returns an array of abstract pathnames denoting the files and directories in the directory denoted by this abstract pathname that satisfy the specified filter.返回一个抽象路径名数组,表示此抽象路径名表示的目录中满足指定过滤器的文件和目录。按指定过滤器过滤文件或文件夹,返回 false 的会被过滤掉,然后拿着过滤得到的文件或文件夹创建 File 对象返回。这里跟 FilenameFilter 不同的是,这个回调是 path (通过 getPath() 得到的)所对应的 FIle 对象,而 FilenameFilter 有两个参数,第一个是调用者,第二个是名称(通过 getName 得到的那个)。详情看 2.3.35
File [] listFiles(FilenameFilter filter)Returns an array of abstract pathnames denoting the files and directories in the directory denoted by this abstract pathname that satisfy the specified filter.返回一个抽象路径名数组,表示此抽象路径名表示的目录中满足指定过滤器的文件和目录。根据 FilenameFilter 的方式过滤文件夹下的子级(直接),然后再根据这些子级创建 File 对象。
static File [] listRoots()List the available filesystem roots.列出可用的文件系统根目录。也就是返回文件系统根目录,比如我的电脑 MAC ,返回的是 [/] ;而 Windows 则有多个,比如 C 盘; D 盘等等。
boolean mkdir()Creates the directory named by this abstract pathname.创建以此抽象路径名命名的目录。根据 path 创建文件夹,如果存在多级目录不存在,那么创建失败;如果所创建文件所属文件夹并没有权限,那么创建失败。
boolean mkdirs()Creates the directory named by this abstract pathname, including any necessary but nonexistent parent directories.创建以此抽象路径名命名的目录,包括任何必要但不存在的父目录。跟上面相同,不同的是可以创建多级文件夹,也就是 a/b/c/d 中,即便只有 a 文件夹存在,那么也能将其余文件夹创建成功。
boolean renameTo(File dest)Renames the file denoted by this abstract pathname.重命名此抽象路径名表示的文件。对文件进行重命名。没有权限的文件夹不能操作;如果文件所属的文件夹有权限,那么此文件有没有权限都是可以操作的。重命名只能在当前的文件夹下,不能像 mv 指令那样使用。不存在的文件毫不犹豫的失败。
boolean setExecutable(boolean executable)A convenience method to set the owner's execute permission for this abstract pathname.设置所有者对此抽象路径名执行权限的便捷方法。文件所有者修改文件的可执行权限,只能修改 [所有者][群组][其他用户] 中的 [所有者] 可执行权限。
boolean setExecutable(boolean executable,boolean ownerOnly)Sets the owner's or everybody's execute permission for this abstract pathname.设置所有者或每个人对此抽象路径名的执行权限。目前我电脑测试的结果跟 boolean setExecutable(boolean executable) 相同。
boolean setLastModified(long time)Sets the last-modified time of the file or directory named by this abstract pathname.设置以此抽象路径名命名的文件或目录的最后修改时间。修改文件的最近一次修改时间。
boolean setReadable(boolean readable)A convenience method to set the owner's read permission for this abstract pathname.为这个抽象路径名设置所有者读取权限的便捷方法。文件所有者修改文件的可执行权限,只能修改 [所有者][群组][其他用户] 中的 [所有者] 可读权限。
boolean setReadable(boolean readable,boolean ownerOnly)Sets the owner's or everybody's read permission for this abstract pathname.设置所有者或每个人对此抽象路径名的读取权限。目前我电脑测试的结果跟 boolean setReadable(boolean readable) 相同。
boolean setReadOnly()Marks the file or directory named by this abstract pathname so that only read operations are allowed.标记由此抽象路径名命名的文件或目录,以便只允许读取操作。设置文件为可读,也就是将文件的可写权限删除,其他权限不动。具体看 2.3.10
boolean setWritable(boolean writable)A convenience method to set the owner's write permission for this abstract pathname.为这个抽象路径名设置所有者写权限的便捷方法。文件所有者修改文件的可执行权限,只能修改 [所有者][群组][其他用户] 中的 [所有者] 可写权限。
boolean setWritable(boolean writable,boolean ownerOnly)Sets the owner's or everybody's write permission for this abstract pathname.设置所有者或每个人对此抽象路径名的写权限。目前我电脑测试的结果跟 boolean setWritable(boolean writable) 相同。
Path ****toPath()Returns a java.nio.file.Path object constructed from the this abstract path.返回从这个抽象路径构造的 java.nio.file.Path 文件路径对象。转换成 Path 对象。
String ****toString()Returns the pathname string of this abstract pathname.返回此抽象路径名的路径名字符串。getPath 相同。
URI ****toURI()Constructs a file: URI that represents this abstract pathname.构造表示此抽象路径名的文件 URI 。转成成 URI 对象。
  1. 代码示例展示

这里将上面的 API 都进行代码展示,并给出输出结果,然后在得出结论和相关的用处说明。

2.1 属性示例

2.1.1 pathSeparator

// 源码展示
public static final String pathSeparator = String.valueOf(pathSeparatorChar);
// 示例展示
System.out.println(File.pathSeparator); // Unix :    WIndow ;

2.1.2 pathSeparatorChar

// 源码展示
public static final char pathSeparatorChar = fs.getPathSeparator();
// 示例展示
System.out.println(File.pathSeparatorChar); // Unix :    WIndow ;

2.1.3 separator

// 源码展示
public static final String separator = String.valueOf(separatorChar);
// 示例展示
System.out.println(File.separator); // Unix /    WIndow \

2.1.4 separatorChar

// 源码展示
public static final char separatorChar = fs.getSeparator();
// 示例展示
System.out.println(File.separatorChar); // Unix /    WIndow \

2.2 构造函数示例

构造函数都只是将传入的参数保存为 pathprefixLength 这两个私有属性,所以只要你是字符串都是不会报错的,其路径是否真的有效,还得看调用具体的方法才能清楚;不然预先判断你传入路径的正确性,在 Java 层面即便在具体的操作也不会判断其正确性,其底层是调用的 native 代码,只有抛出了 IO 异常才能知道有没有错误。

2.2.1 File(String pathname)

// 通过路径名称创建 File 对象
File file = new File("./"); // 使用相对路径创建 File ,也可以直接传入文件夹名称,就像 test 
File file = new File("test");
File file = new File("/test");

其实只要是符合路径规范的字符串都是可以传入的,只不过内部会判断传入的是相对路径还是绝对路径;如果 / 开头就会判断为绝对路径,否则相对路径。如果传入的是 null ,那么就会直接抛 NullPointerException 异常。

之所以只要是符合路径的字符串都是可以的,这是因为对文件的具体操作在方法中,初始化只会保存两个局部变量 pathprefixLength ;其中 path 我们可以直接通过 file.getPath() 来拿到,至于 prefixLength 是内部使用的。

由于要求的字符串,这就意味着只要我们传入的是字符串就可以,所以你可能会传入 "" ,字符串,这样也是不会报错的,但是空字符串在调用一些方法是不可以的。

也可以传入“ ~ ”这个字符串,但是这也会被当做最普通的字符串,也就是说如果你在此基础上创建文件夹和文件都会得到 ~ 这样的文件或文件夹。

2.2.2 File(String parent, String child)

也就是将这两个路径组合在一起,可以理解为传入的两个参数会变成 parent/child 的形式。

File file = new File("test", "childrenTest");
// 如果打印 getPath 的话,可以得到 test/childrenTest
// 这种情况下,第一个参数可以为 null ,当为空的时候就相当于 2.2.1 构造函数
File file = new File(null, "test");
// 如果打印 getPath 的话,得到的是 test

这两个的取值都是字符串,跟 2.2.1 比起来就是第一个参数可以为空,而第二个参数则跟 2.2.1 完全相同;如果第一个参数为空字符串,也就是 "" 的情况下会发生什么呢,如果这样做,会把第二个参数看成是绝对路径的一部分,也就是如果我这样:

File file = new File("", "childrenTest");
// 此时打印 getPath 的话,就会得到 /childrenTest

2.2.3 File(File parent, String child)

这个也跟 2.2.2 差不多,只不过多了将 parent File 对象的路径拿到然后再进行拼接。

File file = new File("parentTest");
File fileChild = new File(file, "test");
// 如果打印 fileChild 的 getPath 的话,那么得到的就是 parentTest/test

总体的规则跟 2.2.2 一样,都是多了一步会取 parent File 中的 path 属性。

2.2.4 File(URI uri)

跟 2.2.3 一样也是将 uri 转换成 path

2.3 方法的示例

2.3.1 boolean canExecute()

判断 File 是否是一个可执行文件。

File file = new File("/Applications/Xcode.app");
System.out.println(file.canExecute()); // true

我安装了 Xcode ,所以这里返回为 true ;下面我们看看一个普通的文本,也就是 txt 文件,我们知道这个肯定不是,我们在代码里面看看:

File file = new File("./test.txt");
System.out.println(file.canExecute()); // false

我在项目下新建了一个文件 test.txt ,然后在这里写入一些文本 "hello world" ,结果执行这个代码,返回了期待的值 false 。下面我们新建一个 shell 脚本文件,看看代码:

#!/bin/bash
echo "hello world"

这是 shell 脚本,我放在了项目下,文件名称为: test-shell.sh

File file = new File("./test-shell.sh");
System.out.println(file.canExecute()); // false

可以看到结果是 false ,但是我在 idea 里面运行发现是可以的,为啥会这样,接下来我尝试去终端中运行:

fileLearn@wujingyue:~$ ./test-shell.sh
# 结果为: zsh: permission denied: ./test-shell.sh

发现出现了错误。然后我尝试使用 sh ./test-shell.sh ,其中 sh 是专门用来执行 shell 脚本的;

fileLearn@wujingyue:~$ sh ./test-shell.sh
# 结果为: hello world

发现是可以的,那问题出在哪里,我们通过执行 ll 查看一下这个文件的权限:

fileLearn@wujingyue:~$ ll
# 结果: -rw-r--r--@ 1 wujingyue  staff    31B Jun 11 21:43 test-shell.sh

我们看到并没有可执行权限,我们尝试先给文件添加可执行权限:

fileLearn@wujingyue:~$ chmod 755 ./test-shell.sh
fileLearn@wujingyue:~$ ./test-shell.sh
# 结果: hello world

也就是说 sh 默认在终端是不可以执行的,需要赋予可执行权限才能执行。操作这些以后我们再执行上面的 Java 代码:

File file = new File("./test-shell.sh");
System.out.println(file.canExecute()); // true

看到这里有没有觉得这个函数是看文件是不是拥有可执行权限来判断的,我们可以进一步验证,我们把之前不行的 txt 文件也改一下权限,让其拥有可执行的权限:

fileLearn@wujingyue:~$ chmod 755 ./test.txt
fileLearn@wujingyue:~$ ./test.txt
# ./test.txt: line 1: hello: command not found

我们看到执行出现了错误,然后这个时候我们再执行 Java 代码:

File file = new File("./test.txt");
System.out.println(file.canExecute()); // true

果然是我们想的那样。为了进一步证明,我尝试了修改 jpg, zip 等格式,发现仍然遵循上面的结论。如果文件不存在,那么这个函数也是会直接返回 false 的。如果不是我们创建的文件,比如是 root 用户创建的文件或文件夹,那么的得到的结果则为下面的情况:

// 首先使用 root 权限创建文件夹
// sudo mkdir testFolder
// 这里时候我们查看文件夹的权限情况
// drwxr-xr-x@ 2 root       staff    64B Jun 12 21:59 testFolder
// 我们看到都有可执行权限
File file = new File("testFile");
System.out.println(file.canExecute()); // true
// 如果我们尝试修改文件夹的权限,也是让 [所有者][群组][其他用户] 
// 中的其他用户没有可执行权限
// sudo chmod 754 testFolder
// drwxr-xr--@ 2 root       staff    64B Jun 12 21:59 testFolder
System.out.println(file.canExecute()); // true
// 然后我们再把文件夹的群组权限也修改掉
// sudo chmod 744 testFolder
// drwxr--r--@ 2 root       staff    64B Jun 12 21:59 testFolder
System.out.println(file.canExecute()); // false

可以发现执行的结果,主要看当前用户所在 [所有者权限][群组权限][其他用户权限] 分组中的权限,如果所在分组里面有可执行权限,那么就会返回 true

2.3.2 boolean canRead()

判断文件是否有可读的权限。根据上面的,我们主要做三种练习,不存在的文件;文件存在但是没有可读权限;文件存在有可读权限。

File file = new File("06.jpg");
System.out.println(file.canRead()); // false

这里的“06.jpg”文件并不存在,所以不存在的文件直接返回 false

// 我先将我的文件 01.jpg 的权限修改为: 000
// fileLearn@wujingyue:~$ chmod 000 ./01.jpg
// fileLearn@wujingyue:~$ ll
// ----------  1 wujingyue  staff    13K Jun 11 22:20 01.jpg
File file = new File("01.jpg");
System.out.println(file.canRead()); // false

然后我们再将文件的权限修改成可执行的权限。

// fileLearn@wujingyue:~$ chmod 400 ./01.jpg
// fileLearn@wujingyue:~$ ll
// -r--------@ 1 wujingyue  staff    13K Jun 11 22:20 01.jpg
File file = new File("01.jpg");
System.out.println(file.canRead()); // true

2.3.3 boolean canWrite()

判断文件是否具有可写入的权限。跟上面相同的练习。

// 在上面我已经将文件的可写入权限去掉
File file = new File("01.jpg");
System.out.println(file.canRead()); // false

// fileLearn@wujingyue:~$ chmod 200 ./01.jpg
// fileLearn@wujingyue:~$ ll
// --w-------  1 wujingyue  staff    13K Jun 11 22:20 01.jpg
System.out.println(file.canRead()); // true

2.3.4 boolean setExecutable(boolean executable)

在上面都是通过使用终端命令: chmod 755 ./01.jpg 来给文件赋予权限的,为了方便理解,这里就通过程序来给文件添加对应的权限。

给文件添加可执行的权限。

File file = new File("01.jpg");
System.out.println(file.canExecute()); // false
file.setExecutable(true);
System.out.println(file.canExecute()); // true

我们这里并没有接收函数的返回值,一般 idea 会提示我们接收其返回值,之所以有返回值,主要是可以用来判断此次行为是否生效。下面我们来看怎样的会导致失败。

File file = new File("05.jpg");
System.out.println(file.canExecute()); // false
file.setExecutable(true);
System.out.println(file.canExecute()); // false

我并没有“05.jpg”这个文件,所以 setExecutable 的结果为 false 。下面我使用 sudo 权限新建一个文件夹 testFolder ,然后通过 sudo chmod 744 testFolder 来改变文件夹的权限,让群组和其他没有可执行的权限,这种情况下,我们再调用看看情况:

File file = new File("testFolder");
System.out.println(file.canExecute()); // false
System.out.println(file.setExecutable(true)); // false
System.out.println(file.canExecute()); // false

我尝试使用 sudo 权限再新建一个普通文本,然后再看看其情况:

// fileLearn@wujingyue:~$ sudo touch testFile
// -rw-r--r--@ 1 root       staff     0B Jun 12 21:27 testFile
File file = new File("testFile");
System.out.println(file.canExecute()); // false
System.out.println(file.setExecutable(true)); // false
System.out.println(file.canExecute()); // false

我们看到结果都是 false ;因为其他用户创建的文件,其他用户没有修改的权限,也就是可写入的权限;下面我们使用 sudo 来修改文件权限,让其他用户权限中有可写入的权限。

// fileLearn@wujingyue:~$ chmod 646 testFile
// -rw-r--rw-@ 1 root       staff     0B Jun 12 21:27 testFile
File file = new File("testFile");
System.out.println(file.canExecute()); // false
System.out.println(file.setExecutable(true)); // false
System.out.println(file.canExecute()); // false

可以看到即便拥有写入权限,并且我们这里跟文件所有者的权限相等,但是非 root 权限用户都是没有权限修改其可执行性的。也就是对于目前来说,其能成功的情况有:

  • 文件存在并且有权限。

不成功的情况有:

  • 文件不存在;
  • 不是文件的所有者都是不能修改的。

这里要说明的是,如果只是 file.canExecute() 来判断函数的可执行权限,这里只要执行程序的用户所在分组有可执行权限,都会返回 true ,这跟 file.setExecutable(true) 不同。

2.3.5 boolean setExecutable( boolean executable, boolean ownerOnly)

根据上面的函数 boolean setExecutable(boolean executable) 得出的结论是不是文件的所有者都是不成功的,因为上面的函数其实也是调用的这个函数,只不过后面的 ownerOnly 参数值为 true

这个函数经过我用我的 MAC 电脑测试,发现跟上面的函数一样。

2.3.6 boolean setReadable(boolean readable)

这个跟上面的可执行权是一样的;也就是文件所有者可以对其操作。

2.3.7 boolean setReadable(boolean readable, boolean ownerOnly)

跟 2.3.5 相同,只不过这个是可读权限。

2.3.8 boolean setWritable(boolean writable)

跟 2.3.6 相同,只不过这个是可写入权限。

2.3.9 boolean setWritable(boolean writable, boolean ownerOnly)

跟 2.3.5 相同,只不过这个是可写入权限。

2.3.10 boolean setReadOnly()

文件所有人将文件的权限改成仅可读权限。会将文件的可写入权限删除掉,可读取的权限保持不变,也就是说如果原本就没有读取的权限,那么执行的结果仍然是不可读的权限。可执行权限同样不受影响。

/*
会将文件的可写入权限删除掉,其他权限保持不变,
也就是这个函数其实修改的写入权限(删除写入权限)
跟上面的 boolean setWritable(boolean writable) 不同
这个会将 [所有者][群组][其他用户] 三种角色
的写入权限都删除掉。
*/
// -rw-rw-rw-@ 1 wujingyue  staff     0B Jun 13 20:59 test
File file = new File("test");
System.out.println(file.setReadOnly());
// -r--r--r--@ 1 wujingyue  staff     0B Jun 13 20:59 test

如果文件本身有所有的 [ 可读可写可执行 ] 权限:

// -rwxrwxrwx@ 1 wujingyue  staff     0B Jun 13 20:59 test
File file = new File("test");
System.out.println(file.setReadOnly());
// -r-xr-xr-x@ 1 wujingyue  staff     0B Jun 13 20:59 test

至于执行失败的情况,跟上面相同。

2.3.11 int compareTo(File pathname)

跟字符串的 compareTo 函数相同;只不过这里取的是 File 对象 path 属性,而 path 属性是我们传入的字符串。具体看函数的源代码:

public int compareTo(File pathname) {
    return fs.compare(this, pathname);
}
@Override
public int compare(File f1, File f2) {
    return f1.getPath().compareTo(f2.getPath());
}

这里的 getPath 是获取文件的路径(具体见 2.3.12 ),而这里的路径也就是我们传入的字符串。

File file1 = new File("test1");
File file2 = new File("test1");
System.out.println(file1.getPath()); // test
System.out.println(file2.getPath()); // test
System.out.println(file1.compareTo(file2)); // 0

可能有人觉得是两个文件是否指同一个文件:

File file1 = new File("test1");
File file2 = new File(file1.getAbsolutePath());
System.out.println(file1.getPath()); // test1
System.out.println(file2.getPath()); // /Users/wujingyue/Learns/java/learn-project/fileLearn/test1
System.out.println(file1.compareTo(file2)); // 69

这里的 file1.getAbsolutePath() 是文件 file1 的绝对路径,这样两个文件就是指同一个文件。

2.3.12 String ****getPath()

得到文件的路径,这里指的是创建 File 对象传入的 pathname 参数。

File file1 = new File("test1");
System.out.println(file1.getPath()); // test1

File file1 = new File("/test1/1/2/3");
System.out.println(file1.getPath()); // /test1/1/2/3

File file1 = new File("C:\test\1\2\3\4");
System.out.println(file1.getPath()); // C:\test\1\2\3\4

File file1 = new File("C:\test\1\2\3\4");
File file2 = new File(file1.getAbsolutePath());
System.out.println(file1.getAbsolutePath()); // /Users/wujingyue/Learns/java/learn-project/fileLearn/C:\test\1\2\3\4
System.out.println(file2.getPath()); // /Users/wujingyue/Learns/java/learn-project/fileLearn/C:\test\1\2\3\4

关于 getAbsolutePath 函数,具体查看 2.3.13

2.3.13 String ****getAbsolutePath()

获取文件的绝对位置。

File file1 = new File("test");
System.out.println(file1.getAbsolutePath()); // /Users/wujingyue/Learns/java/learn-project/fileLearn/test

如果传入的本身就是绝对路径,那么就直接使用我们传入的:

File file1 = new File("/test/1/2");
System.out.println(file1.getAbsolutePath()); // /test/1/2

可能你觉得我传入的不是真实的路径,的确我的电脑上没有这个路径,但是 File 本身不去做相关校验,原本 File 也不知道其真实意图,比如你传入的路径虽然不存在,但是将来你可能拿着这个地址创建相应的文件夹和文件。

2.3.14 String ****getName()

获取路径的名称,也就是我们传入的最后一个 / 后的字符串。我们直接看源码:

public String getName() {
    // 从后往前找分隔符第一次出现的下标
    int index = path.lastIndexOf(separatorChar);
    if (index < prefixLength) return path.substring(prefixLength);
    //index 到最后的字符串返回
    return path.substring(index + 1);
}

接下来我们来看例子:

File file1 = new File("test");
System.out.println(file1.getName()); // test

File file1 = new File(".");
System.out.println(file1.getName()); // .

File file1 = new File("../");
System.out.println(file1.getName()); // ..

File file1 = new File("/User/wujingyue/Learn");
System.out.println(file1.getName()); // Learn

File file1 = new File("test/Learn/java/file");
System.out.println(file1.getName()); // file

2.3.15 File ****getAbsoluteFile()

使用文件的绝对路径来创建新的 File 对象。这个函数也是看源码能更好的明白:

public File getAbsoluteFile() {
    // 获取当前文件的绝对路径
    String absPath = getAbsolutePath();
    if (getClass() != File.class) {
        absPath = fs.normalize(absPath);
    }
    // 使用绝对路径新建 File 对象
    return new File(absPath, fs.prefixLength(absPath));
}

下面再看看示例:

File file1 = new File("test/Learn/java/file");
File absoluteFile = file1.getAbsoluteFile();
System.out.println(file1.getPath()); // test/Learn/java/file
System.out.println(file1.getAbsolutePath()); // /Users/wujingyue/Learns/java/learn-project/fileLearn/test/Learn/java/file
System.out.println(absoluteFile.getPath()); // /Users/wujingyue/Learns/java/learn-project/fileLearn/test/Learn/java/file

2.3.16 String ****getCanonicalPath()

返回此 FIle 的规范路径名称,此名称是绝对路径。不管在初始化传入的名称是相对路径还是绝对路径,这个的输入都是绝对路径。

File file1 = new File("test");
try {
    System.out.println(file1.getCanonicalPath()); // /Users/wujingyue/Learns/java/learn-project/fileLearn/test
} catch (IOException e) {
    throw new RuntimeException(e);
}

所谓的规范的路径名称,也就是如果路径中包含像 ... 这样的符号,都会转换成路径:

File file1 = new File(".");
try {
    System.out.println(file1.getCanonicalPath());// /Users/wujingyue/Learns/java/learn-project/fileLearn
    // 如果是 ../../ ,则输出为: /Users/wujingyue/Learns/java
} catch (IOException e) {
    throw new RuntimeException(e);
}

除了上面的,还有文件的软链接会显示文件/目录的真实路径,而不是软链接的路径。

// 先将文件的软链接创建好
// ln -s ~/Downloads/Auto-GPT-0.3.1 ./testlns
File file1 = new File("testlns");
try {
    System.out.println(file1.getCanonicalPath());
    // 输出结果:/Users/wujingyue/Downloads/Auto-GPT-0.3.1
} catch (IOException e) {
    throw new RuntimeException(e);
}

说到软链接,可能会想到硬链接,硬链接不受影响。

2.3.17 File ****getCanonicalFile()

跟上面相同,只不过这个是拿到规范的路径后创建一个 File 对象返回。

File file1 = new File("testlns");
try {
    File file2 = file1.getCanonicalFile();
    System.out.println(file1.getAbsolutePath()); // /Users/wujingyue/Learns/java/learn-project/fileLearn/testlns
    System.out.println(file1.getCanonicalPath()); // /Users/wujingyue/Downloads/Auto-GPT-0.3.1
    System.out.println(file2.getPath()); // /Users/wujingyue/Downloads/Auto-GPT-0.3.1
} catch (IOException e) {
    throw new RuntimeException(e);
}

下面我们再看看源码,进一步验证我们的说法:

public File getCanonicalFile() throws IOException {
    // 得到 path 得到规范路径
    String canonPath = getCanonicalPath();
    if (getClass() != File.class) {
        canonPath = fs.normalize(canonPath);
    }
    // 拿着路径创建 File 对象
    return new File(canonPath, fs.prefixLength(canonPath));
}

2.3.18 boolean isAbsolute()

判断 Filepath 是不是绝对路径,如果是绝对路径就返回 true ,否则返回 false 。在我的电脑上( MAC ),只要路径是 / 开头的会返回 true ,其他的则为 false

File file1 = new File("//");
System.out.println(file1.isAbsolute()); // true

File file1 = new File("/");
System.out.println(file1.isAbsolute()); // true

File file1 = new File("123");
System.out.println(file1.isAbsolute()); // false

File file1 = new File("abc");
System.out.println(file1.isAbsolute()); // false

File file1 = new File("!");
System.out.println(file1.isAbsolute());

2.3.19 boolean isDirectory()

判断 File 是不是文件夹。

// 先查看当前目录的各个文件的情况
// ll
/*
--wx------  1 wujingyue  staff    13K Jun 11 22:20 01.jpg
lrwxr-xr-x@ 1 wujingyue  staff    52B Jun 19 21:03 02.jpg -> /Users/wujingyue/Downloads/飞书20230611-215059.jpg
-rw-r--r--@ 1 wujingyue  staff   423B Jun 11 14:50 fileLearn.iml
drwxr-xr-x@ 2 wujingyue  staff    64B Jun 12 21:15 folder
drwxr-xr-x@ 3 wujingyue  staff    96B Jun 11 15:06 out
-rw-r--r--@ 2 wujingyue  staff    13K Jun 11 21:50 pp.jpg
drwxr-xr-x@ 4 wujingyue  staff   128B Jun 19 20:56 src
-rw-r--r--@ 1 root       staff     0B Jun 13 21:36 test
lrwxr-xr-x@ 1 wujingyue  staff    41B Jun 18 20:51 testlns -> /Users/wujingyue/Downloads/Auto-GPT-0.3.1
*/
// 当是软链接的情况,本身是文件夹
File file1 = new File("testlns");
System.out.println(file1.isDirectory()); // true

// 当本身不存在的路径
File file1 = new File("test11");
System.out.println(file1.isDirectory()); // false

// 当路径是文件的时候
File file1 = new File("test");
System.out.println(file1.isDirectory()); // false

// 本身就是文件夹
File file1 = new File("src");
System.out.println(file1.isDirectory()); // true

2.3.20 boolean isFile()

判断 path 是否为文件。

// 目录情况跟上面的 2.3.19 相同
// 当是文件的时候
File file1 = new File("test");
System.out.println(file1.isFile()); // true

// 当是文件夹的时候
File file1 = new File("src");
System.out.println(file1.isFile()); // false

// 当路径不存在的时候
File file1 = new File("src1");
System.out.println(file1.isFile()); // false

2.3.21 boolean isHidden()

判断路径是不是处于隐藏的状态。

/*
先看看目录情况
drwxr-xr-x@ 13 wujingyue  staff   416B Jun 19 21:03 .
drwxr-xr-x   4 wujingyue  staff   128B Jun 12 21:19 ..
-rw-r--r--@  1 wujingyue  staff   344B Jun 11 14:50 .gitignore
drwxr-xr-x@  6 wujingyue  staff   192B Jun 11 15:06 .idea
--wx------   1 wujingyue  staff    13K Jun 11 22:20 01.jpg
lrwxr-xr-x@  1 wujingyue  staff    52B Jun 19 21:03 02.jpg -> /Users/wujingyue/Downloads/飞书20230611-215059.jpg
-rw-r--r--@  1 wujingyue  staff   423B Jun 11 14:50 fileLearn.iml
drwxr-xr-x@  2 wujingyue  staff    64B Jun 12 21:15 folder
drwxr-xr-x@  3 wujingyue  staff    96B Jun 11 15:06 out
-rw-r--r--@  2 wujingyue  staff    13K Jun 11 21:50 pp.jpg
drwxr-xr-x@  4 wujingyue  staff   128B Jun 19 21:09 src
-rw-r--r--@  1 root       staff     0B Jun 13 21:36 test
lrwxr-xr-x@  1 wujingyue  staff    41B Jun 18 20:51 testlns -> /Users/wujingyue/Downloads/Auto-GPT-0.3.1
*/
// 处于隐藏的文件
File file1 = new File(".gitignore");
System.out.println(file1.isHidden()); // true

// 不隐藏的文件
File file1 = new File("test");
System.out.println(file1.isHidden()); // false

// 路径不存在
File file1 = new File("test1");
System.out.println(file1.isHidden()); // false

2.3.22 boolean mkdir()

根据 path 创建文件夹,如果存在多级文件夹不存在,那么返回 false ,在有权限的情况下只有最后的文件夹( /a/b/c 中的 c )不存在能成功创建文件夹并返回 true

// 在当前文件夹下创建文件夹,原本文件夹不存在
File file1 = new File("test1");
System.out.println(file1.mkdir()); // true

// 在当前文件夹下,原本文件夹存在
File file1 = new File("test");
System.out.println(file1.mkdir()); // false

// 在当前文件下,原本是文件的
File file1 = new File("01.jpg");
System.out.println(file1.mkdir()); // false

// 在当前文件下,多级文件夹不存在
File file1 = new File("src/test1/test2");
System.out.println(file1.mkdir()); // false

// 在没有权限的文件夹下创建文件夹
// sudo mkdir test2
// drwxr-xr-x@ 2 root       staff    64B Jun 19 21:28 test2
File file1 = new File("test2/test3");
System.out.println(file1.mkdir()); // false

2.3.23 boolean mkdirs()

递归创建文件夹,也就是创建多级文件夹;其余跟上面的 boolean mkdir() 相同。

// 其中 b/c/d 都不存在
File file1 = new File("test1/b/c/d");
System.out.println(file1.mkdirs()); // true

2.3.24 boolean createNewFile()

创建文件。在所属文件夹存在并且有权限的情况下才能成功。

// 在已有路径中创建文件
File file1 = new File("test3");
System.out.println(file1.createNewFile()); // true

// 在路径不存在的文件夹中创建文件
File file1 = new File("test4/test5");
System.out.println(file1.createNewFile()); // false

// 在没有权限的文件夹下创建文件
File file1 = new File("test2/test5");
System.out.println(file1.createNewFile()); // false

// 文件本身已经存在
File file1 = new File("test");
System.out.println(file1.createNewFile()); // false

2.3.25 static File ****createTempFile(String prefix, String suffix)

创建包含指定文件前缀和后缀的临时文件。

File test1 = File.createTempFile("test", ".txt");
System.out.println(test1.getPath()); // /var/folders/qt/_fb3rrpn2vgg3jk637w_v1d80000gn/T/test10152188375744504308.txt

2.3.26 static File ****createTempFile(String prefix, String suffix, File directory)

在给出的文件夹中创建包含指定文件前缀和后缀的文件。在创建文件方面跟 boolean createNewFile() 相同,在创建的文件名称方面跟 static File ****createTempFile(String prefix, String suffix) 相同。

// 在当前文件夹下创建文件
File test1 = File.createTempFile("test", ".txt", new File("."));
System.out.println(test1.getPath()); // ./test2146915152605759112.txt

// 当给定的 File 文件夹不存在的时候会抛出异常
File test1 = File.createTempFile("test", ".txt", new File("./test3"));
System.out.println(test1.getPath());
// Exception in thread "main" java.lang.RuntimeException: java.io.IOException: Not a directory

2.3.27 boolean delete()

删除文件或文件夹。我特意测试了一下,即便这个文件夹或文件并没有权限也是可以删除的,这点我没有想明白,但是运行的结果是这样的。只不过我发现如果删除的文件或文件夹所属的文件夹没有权限,那么删除下面的文件或文件夹就会失败

// 删除存在的文件
File file = new File("test");
System.out.println(file.delete()); // true

// 删除存在的文件夹
File file = new File("test2");
System.out.println(file.delete()); // true

// 删除不存在的文件或文件夹
File file = new File("test5");
System.out.println(file.delete()); // false

// 删除包含文件的文件夹 test2/1.txt
File file = new File("test2");
System.out.println(file.delete()); // false

// 删除包含文件夹的文件夹 test1/b/c/d
File file = new File("test1");
System.out.println(file.delete()); // false

// -rw-r--r--  1 root   staff     0B Jun 20 10:29 test1.txt
File file = new File("test1.txt");
System.out.println(file.delete()); // true

// drwxr-xr-x  4 root   staff   128B Jun 20 11:04 test
// -rw-r--r--  1 root  staff     0B Jun 20 11:01 01.txt
// drwxr-xr-x  2 root  staff    64B Jun 20 11:04 folder
File file = new File("test/folder");
System.out.println(file.delete()); // false
File file = new File("test/01.txt");
System.out.println(file.delete()); // false

2.3.28 boolean exists()

判断文件或文件夹是否存在。

// 文件夹 test1
File file = new File("test1");
System.out.println(file.exists()); // true

// 文件 01.jpg
File file = new File("01.jpg");
System.out.println(file.exists());

// 不存在的文件或文件夹
File file = new File("03.jpg");
System.out.println(file.exists()); // false

2.3.29 void deleteOnExit()

当虚拟机退出的删除,这个跟 boolean delete() 不同的是时间, delete 是立即删除,deleteOnExit 则是虚拟机退出后再删除。其余跟 delete 保持相同。

// 删除存在的文件夹
File file = new File("test2");
file.deleteOnExit();
while(true){}
// 只要我不结束程序,这个文件夹一直存在,当我按下 control + c 就会发现文件夹被删除了

// 删除存在的文件
File file = new File("test.txt");
file.deleteOnExit();
while(true){}

// 删除不存在文件或文件夹,看不出任何效果,本来文件或文件夹就不存在
// 删除没有权限的文件或文件夹也是没啥表示,反正文件或文件夹还存在

2.3.30 String ****getParent()

得到当前文件或文件夹的父级文件夹。

File file = new File("test1/1");
System.out.println(file.getParent()); // test1

File file = new File("test1");
System.out.println(file.getParent()); // null

File file = new File("test2/1/2/3/4");
System.out.println(file.getParent()); // test2/1/2/3

File file = new File("/test2/1/2/3/4");
System.out.println(file.getParent()); // /test2/1/2/3

2.3.31 long lastModified()

获取上一次修改的时间,如果文件或文件夹不存在返回 0

// 存在的文件夹
File file = new File("test1");
System.out.println(file.lastModified()); // 1687181825968
// 这个就是我昨天新建的文件夹

// 不存在的文件或文件夹
File file = new File("test2");
System.out.println(file.lastModified()); // 0

可以通过 boolean setLastModified(long time) 来修改这个时间。参数跟返回值一样是毫秒数:

File file = new File("src");
System.out.println(file.lastModified()); // 1687573295654
System.out.println(file.setLastModified(1687273246041L)); // true
System.out.println(file.lastModified()); // 1687273246041

// 能直接修改到未来或过去

2.3.32 long length()

如果是文件,则返回文件的内容的长度(字节);如果是文件夹,空文件 64 ,下面有一级文件夹或文件 96 ,每增加一个文件夹或文件就多 32 ,要是下一级,下一级的下一级不计算在内 (这是在我电脑上的表现,因为官方说了文件夹返回的值是未指定)。

// test.txt 文件内容为:wujingyue
File file = new File("test3/test.txt");
System.out.println(file.length()); // 9

// 空文件夹
File file = new File("test4");
System.out.println(file.length()); // 64

// 直接子级有 5 个
// a         b         c         test.txt  test1.txt
File file = new File("test3");
System.out.println(file.length()); // 224

2.3.33 String [] list()

返回文件夹中的文件和文件夹。

File file = new File("test3");
System.out.println(Arrays.toString(file.list()));
// 返回的数据为: [test1.txt, a, test.txt, c, b]

// 如果传入的是文件
File file = new File("test3/test.txt");
System.out.println(Arrays.toString(file.list())); // null

// 如果传入的是不存在的文件夹或文件
File file = new File("test3/e");
System.out.println(Arrays.toString(file.list())); // null

// 如果传入的是空文件夹
File file = new File("test3/c");
System.out.println(Arrays.toString(file.list())); // []

2.3.34 String [] list(FilenameFilter filter)

返回过滤后的结果,过滤接口为:

public interface FilenameFilter {
    /**
     * Tests if a specified file should be included in a file list.
     *
     * @param   dir    the directory in which the file was found.
     * @param   name   the name of the file.
     * @return  {@code true} if and only if the name should be
     * included in the file list; {@code false} otherwise.
     */
    boolean accept(File dir, String name);
}

accept 返回为 true 的通过过滤,否则会被过滤掉。

File file = new File("test3");
System.out.println(Arrays.toString(file.listFiles((dir, filename) -> true)));
// 得到的结果为:[test3/test1.txt, test3/a, test3/test.txt, test3/c, test3/b]
// 现在就相当于没过滤

// 假如我只想要含有 test 的
File file = new File("test3");
System.out.println(Arrays.toString(file.listFiles((dir, filename) -> filename.contains("test"))));
// 现在的结果就为:[test3/test1.txt, test3/test.txt]

2.3.35 File [] listFiles(FileFilter filter)

返回过滤后的结果,过滤接口为:

public interface FileFilter {

    /**
     * Tests whether or not the specified abstract pathname should be
     * included in a pathname list.
     *
     * @param  pathname  The abstract pathname to be tested
     * @return  {@code true} if and only if {@code pathname}
     *          should be included
     */
    boolean accept(File pathname);
}

这个 accept 的参数跟上面不同,这里是一个子级的 FIle 对象。

File file = new File("test3");
System.out.println(Arrays.toString(file.listFiles((f) -> true)));
// 结果为:[test3/test1.txt, test3/a, test3/test.txt, test3/c, test3/b]

// 跟上面相同过滤掉 a b 这些,保留包含 test
File file = new File("test3");
System.out.println(Arrays.toString(file.listFiles((f) -> f.getName().contains("test"))));
// 结果为:[test3/test1.txt, test3/test.txt]

2.3.36 boolean renameTo(File dest)

对文件或文件夹进行重命名,重命名只能对 path 中的最后一个路径或文件名进行更改,比如 a/b/c 中的 c

// 对文件夹进行重命名
File file = new File("test3");
System.out.println(file.renameTo(new File("test3-new"))); // true

// 对文件进行重命名
File file = new File("testlns");
System.out.println(file.renameTo(new File("test"))); // true

// 对没有权限的文件夹进行重命名
// drwxr-xr-x@ 3 root       staff    96B Jun 20 21:27 test2
File file = new File("test2");
System.out.println(file.renameTo(new File("test2-new"))); // false

// 对没有权限的文件进行重命名
// -rw-r--r--@ 1 root       staff    11B Jun 24 10:07 tianzhidao.txt
File file = new File("tianzhidao.txt");
System.out.println(file.renameTo(new File("tianzhidao1.txt"))); // true

// 在没有权限的文件夹下重命名没有权限的文件夹
File file = new File("test2/tianzhidao.txt");
System.out.println(file.renameTo(new File("test2/123.txt"))); // false

// 重命名的同时修改文件路径
File file = new File("tianzhidao1.txt");
System.out.println(file.renameTo(new File("test/tianzhidao2.txt"))); // false