目录
1. File类的概述
File类,从英文词义上我们就可以了解到这是一个跟文件相关的类,Java把电脑中的文件和文件夹(目录)封装为了一个File类,我们可以使用File类对文件和文件夹进行操作,可以把File类看成是文件和文件夹的抽象表示形式,另外File类是一个与系统无关的类,因此任何的操作系统都可以使用这个类中的方法
1.1 静态成员变量
我们先来了解一下File类中的静态成员变量:
static String pathSeparator:与系统有关的路径分隔符,为了方便,它被表示为一个字符串。
static char pathSeparatorChar:与系统有关的路径分隔符。
static String separator:与系统有关的默认名称分隔符,为了方便,它被表示为一个字符串。
static char separatorChar:与系统有关的默认名称分隔符。
在解释这四个成员变量之前,我们来了解一下什么是路径分隔符和名称分隔符
还记得在安装JDK时候需要配置系统环境变量吗?这变量中的一个个不同的地址,就是利用路径分隔符把它分开的
那什么是名称分隔符呢?这个其实我们已经经常使用了,在任意一个路径下,其多级目录名称的区分就是用的名称分隔符
大家现在已经知道这个分隔符是什么东西了,你可能会觉得我直接打个分号或者直接打个斜杠不就好了吗?假如这个世界上只有Windows操作系统,那是没有问题的,但是还有Linux系统呀,而且问题在于Windows与Linux的路径分隔符与名称分隔符是不同的:
路径分隔符在Windows是分号而在Linux是冒号
名称分隔符在Windows是反斜杠而在Linux是正斜杠
同时,我们知道Java是一门具有跨平台性的语言,因此它在File类中给出了静态成员变量,能够自动获取所对应系统的分隔符是什么,所以我们在码程序的时候使用到路径就不要写死了,什么意思呢?例如我们平时写路径是这样子的(我是Windows系统):
System.out.println("C:\\Users\\Star\\Desktop");
要是我想Linux也能用,那么可以使用静态成员变量:
System.out.println("C:" + File.separator + "Users" + File.separator + "Star" + File.separator + "Desktop");
它们的输出结果是一样的,可是后者具有跨平台性,可以在Linux上使用
1.2 绝对路径与相对路径
绝对路径,是一个完整的路径,我们平常大多是也是使用这个绝对路径,其表达形式大家也很熟悉:
"D:\\IdeaProjects\\study\\practicing\\src\\practice\\java02\\coding\\day09File\\Demo.java"
相对路径,是一个简化的路径,它所相对的是我们IDEA中的project路径,怎么找这个project路径呢?
所以该项目路径是
"D:\\IdeaProjects\\study\\practicing"
使用相对路径在写路径就可以简化为
"src\\practice\\java02\\coding\\day09File\\Demo.java"
另外要注意的是,路径是不区分大小写的
1.3 构造方法
File类的构造方法有三种,其中第一种是最为常用的:
public File(String pathname):通过将给定路径名字符串转换为抽象路径名来创建一个新 File 实例。
public File(String parent, String child):根据 parent 路径名字符串和 child 路径名字符串创建一个新 File 实例。
public File(File parent, String child):根据 parent 抽象路径名和 child 路径名字符串创建一个新 File 实例。
这里要说明几点:
- pathname写的是字符串的路径名称
- 路径可以是文件结尾,也可以是文件夹结尾
- 路径可以是相对路径,也可以是绝对路径
- 路径可以是存在的,也可以是不存在的
- 创建File对象,只是把字符串路径封装为File对象,并不考虑路径的真假情况
下面我们来用一下这几种构造方法
其输出的结果都是一样的
2. File类的成员方法
这里主要介绍四种不同类型功能的成员方法
2.1 获取方法
开门见山,介绍先给你们抛出来:
public String getAbsolutePath():返回此抽象路径名的绝对路径名字符串。
public String getPath():将此抽象路径名转换为一个路径名字符串。
public String getName():返回由此抽象路径名表示的文件或目录的名称。
public long length():返回由此抽象路径名表示的文件的长度。
特别说明一下,无论File中定义的是绝对的还是相对的路径,getAbsolutePath
都会返回绝对路径,而getPath
则是定义什么返回什么,getName
是获取所定义路径的结尾部分(文件/文件夹),length
返回的长度是以字节为单位的,若给出路径不存在则返回0,另外文件夹是没有大小的概念的,因此也是0,下面来使用一下
其输出结果:
2.2 判断方法
常用判断方法的介绍如下:
public boolean exists():测试此抽象路径名表示的文件或目录是否存在。
public boolean isDirectory():测试此抽象路径名表示的文件是否是一个目录。
public boolean isFile():测试此抽象路径名表示的文件是否是一个标准文件。
注意,后两个判断方法的使用前提是路径必须真实存在的,否则都会返回false
,下面来演示一下
看看其输出的结果
2.3 创建方法
前面说File只是把路径封装,不管真假,而其实也可以真正创建或删除一个文件或者文件夹,下面来看看具体方法
public boolean createNewFile():当且仅当不存在具有此抽象路径名指定名称的文件时,不可分地创建一个新的空文件
public boolean mkdir():创建此抽象路径名指定的目录。
public boolean mkdirs():创建此抽象路径名指定的目录,包括所有必需但不存在的父目录。
public boolean delete():删除此抽象路径名表示的文件或目录
注意:
createNewFile
只能创建文件不能创建文件夹,当File封装路径的文件不存在时则创建文件,返回true
,若存在则不会创建,返回false
,另外File中封装的路径必须真实存在,否则会抛出异常mkdir
只能创建单级空文件夹不能创建文件,同样的,文件夹不存在则创建文件夹返回true
,若文件夹存在则不会创建返回false
,另外如果File中封装的路径不存在也会返回false
mkdirs
既可以创建单级空文件夹也可以创建多级文件夹但不能创建文件,同样的,若文件夹不存在则创建返回true
(这时候File中封装的路径就没有真假之分了,原本不存在的路径也能给你创建出来),若文件夹存在则不会创建返回false
delete
可以删除File中封装的文件或文件夹(只能单级),删除成功则返回true
,若文件夹中有内容则不会删除返回false
,若File中封装的路径不存在也返回false
,另外该方法是直接从硬盘删除,不走回收站,要谨慎操作
下面来体验一下
运行的结果显示true
,并且可以看到左侧中也出现了刚刚创建的文件和文件夹
delete
方法可以自行尝试,这里就不演示了
2.4 遍历方法
最后再来介绍一下遍历文件夹的方法
public String[] list():返回一个字符串数组,这些字符串指定此抽象路径名表示的目录中的文件和目录。
public File[] listFiles():返回一个抽象路径名数组,这些路径名表示此抽象路径名表示的目录中的文件。
注意:若File中封装的路径不存在或不是一个文件夹,则会抛出空指针异常
下面还是演示环节
看看结果
相信大家也发现了使用String和File接收返回值是不同的,这里就不过多介绍了
3. File过滤器
在File类中有两个和listFiles
重载的方法:
public File[] listFiles(FileFilter filter):返回抽象路径名数组,这些路径名表示此抽象路径名表示的目录中满足指定过滤器的文件和目录。
public File[] listFiles(FilenameFilter filter):返回抽象路径名数组,这些路径名表示此抽象路径名表示的目录中满足指定过滤器的文件和目录。
方法的参数传递的就是过滤器,分别有两种,FileFilter和FileNameFilter
3.1 FileFilter的使用
先来看看官方介绍是个啥:public interface FileFilter
:用于抽象路径名的过滤器。
很简单,就是用来过滤你想要的文件的,那么怎么用呢?在该接口中有一个accept
方法:
public boolean accept(File pathname):测试指定抽象路径名是否应该包含在某个路径名列表中。
显然接口的方法是需要我们进行重写的,换言之过滤规则是由我们自己来设定,那他内部的工作流程是怎么样的呢?
首先,listFile
会遍历给定的文件夹中的内容,把每一个(文件夹/文件)封装成File对象;然后,listFile
会把每一个File对象传递给accept
方法,由accept
方法中的规则进行过滤,返回值为true
的则放进File数组当中
下面我们来尝试一下把.java
结尾的文件都找出来,这里直接给出示例代码
public class DemoFileFilter {
public static void main(String[] args) {
File file = new File("src");
getFile(file);
}
private static void getFile(File file) {
File[] files = file.listFiles(new FileFilter() {
@Override
public boolean accept(File pathname) {
//获取其真正文件名(文件夹名) 把名字转换为小写(不区分大小写) 判断后缀
if (pathname.getName().toLowerCase().endsWith(".java")) {
return true;
}
return false;
}
});
for (File file1 : files) {
System.out.println(file1);
}
}
}
这里不给出示例结果了,有兴趣的同学自己找个文件目录尝试一下,另外,在上篇文章中介绍了Lambda表达式,现在再复习一下,该示例代码用Lambda表达式优化后是这样子的:
public class DemoFileFilter {
public static void main(String[] args) {
File file = new File("src");
getFile(file);
}
private static void getFile(File file) {
File[] files = file.listFiles(pathname -> {
if (pathname.getName().toLowerCase().endsWith(".java")) {
return true;
}
return false;
});
for (File file1 : files) {
System.out.println(file1);
}
}
}
显然相比原来的代码是简洁了很多
3.2 FileNameFilter的使用
下面再来认识一下另外一个过滤器:public interface FilenameFilter
:实现此接口的类实例可用于过滤器文件名。
这…什么意思呢?不管他,我们先来看看这个接口中的抽象方法,在该接口中同样有一个accept
方法:
public boolean accept(File dir, String name):测试指定文件是否应该包含在某一文件列表中。
显然这个抽象方法跟上一个过滤器不太一样,这里有两个参数,那么这个的工作流程又是怎么样的呢?
首先,listFile
会把构造方法中传递的文件夹封装(赋值)给dir
;然后,listFile
会把遍历该文件夹的内容,把遍历所得的文件名(文件夹名)传递给name
;最后,由accept
方法中的规则进行过滤,返回值为true
的则放进File数组当中
同样的,下面我们来尝试一下把.java
结尾的文件都找出来,这里直接给出示例代码
public class DemoFileNameFilter {
public static void main(String[] args) {
File file = new File("src");
getFile(file);
}
private static void getFile(File file) {
File[] files = file.listFiles(new FilenameFilter() {
@Override
public boolean accept(File dir, String name) {
//重新封装(组合)为一个File对象
File file = new File(dir,name);
if (file.getName().toLowerCase().endsWith(".java")) {
return true;
}
return false;
}
});
for (File file1 : files) {
System.out.println(file1);
}
}
}
这里也不给出示例结果了,有兴趣的同学自己找个文件目录尝试一下
4. 综合案例
前面介绍了遍历方法,这里我们再来了解一下遍历文件夹的高级应用
4.1 遍历多级文件夹
在前面所给出的遍历文件夹的示例当中,只遍历的传递的文件夹中的内容,对于文件夹中的文件夹并没有进一步进行遍历,那么这里就来尝试一下把一个文件夹中包含的所有内容都给遍历出来
怎么实现这个功能呢?先来捋一捋思路,是靠什么决定我要不要进一步往下遍历呢?是依靠类型来判断对吧?那么,我们就可以调用File中的判断方法,让其判断是文件夹时则也对这个文件夹进行遍历(递归调用)
下面来看看示例代码
再来看一下运行结果(太长了只截取部分)
体验不够明显?来看一眼src文件夹中有什么你就感受深刻了,src文件夹下只有practice这个文件夹(bug.txt那些文件与src文件夹是同级的,不要混淆),若按照2.4中的遍历方法进行遍历,那么只会遍历出这个文件夹,但本节所介绍的方法,可以把其所有子文件夹的内容也遍历出来
4.2 遍历多级文件夹并过滤
是不是还不够过瘾?刚刚遍历出来的内容中有文件夹,也有文件,那么现在我就只想要java文件,我们来过滤一把
示例代码直接上
看看运行结果,这时候全都是java文件了
细心的同学可能发现了,怎么没有用过滤器?是不是都以为我会写过滤器呢?其实我是特意而为之,我个人觉得某些情况下不用他的过滤器,自己写过滤规则更方便简洁,有兴趣的同学可以自己用过滤器写写该代码相互对比一下
至此,File类有关的内容基本上介绍完了,这篇文章的内容相对还是比较简单的,溜了溜了~