day08【File类、递归】
主要内容
- File类
- 递归
- 过滤器
教学目标
- 能够说出File对象的创建方式
- 能够说出File类获取名称的方法名称
- 能够说出File类获取绝对路径的方法名称
- 能够说出File类获取文件大小的方法名称
- 能够说出File类判断是否是文件的方法名称
- 能够说出File类判断是否是文件夹的方法名称
- 能够辨别相对路径和绝对路径
- 能够遍历文件夹
- 能够解释递归的含义
- 能够使用递归的方式计算5的阶乘
- 能够说出使用递归会内存溢出隐患的原因
第一章 File类
1.1 概述
目标
- 能够理解File类的具体作用。
生活中计算机中包含了文件和文件夹这两类事物,Java有对应的类来对计算机中的文件和文件夹进行操作处理。
-
java.io.File :文件和目录路径名的抽象表示,主要用于文件和目录的创建、查找和删除等操作。
创建一个文件或文件夹
删除一个文件或文件夹
获取一个文件或文件夹
获取文件的大小
判断文件或文件夹是否存在
对文件夹进行遍历 -
重点记住3个单词:
- file:文件相关的操作。
- directory:文件夹相关的操作。
- path:路径相关的操作。
小结
File类主要是对持久设备上的文件和文件夹进行创建、删除、遍历等操作。它不能去操作文件中的数据。当我们需要操作持久设备上的文件或文件夹时就直接找File类完成,如果要操作文件中的数据只能找后面需要学习的IO技术搞定。
1.2 成员变量
目标
- 能够明确File类的成员变量的作用,和了解计算机中的路径。
- 成员变量:
- static String pathSeparator 获取系统相关的路径分隔符字符,为方便操作,表示为字符串。
- static char pathSeparatorChar 获取与系统相关的路径分隔符,表示为字符。
- static String separator 获取系统相关的文件名称分隔符,以方便的方式表示为字符串。
- static char separatorChar 获取系统相关的文件名称分隔符,表示为字符。
步骤
- 调用File类的静态成员获取对应的路径和文件名称分隔符,然后输出打印查看结果。
实现
/*
演示File类的静态成员变量
static String pathSeparator 与系统相关的路径分隔符字符,为方便起见,表示为字符串。
static char pathSeparatorChar 与系统相关的路径分隔符。
第一天学习的path变量配置中使用的,用来分隔不同的路径配置。
static String separator 与系统相关的默认名称 - 分隔符字符,以方便的方式表示为字符串。
static char separatorChar 与系统相关的默认名称分隔符。
*/
public class FileFiledsDemo {
public static void main(String[] args) {
// 获取路径分隔符
String pathSeparator = File.pathSeparator;
System.out.println("pathSeparator = " + pathSeparator); // ;
// 获取文件名称分隔符
String separator = File.separator;
System.out.println("separator = " + separator); // \
}
}
小结
File类的成员变量主要是获取系统相关的路径分隔符 和 文件名称分隔符。而不同的 操作系统路径和目录的分隔符会有所不同。所以一般我们不会将分隔符的符号写死。而是通过File类的成员变量获取。 参考代码
/*
路径分隔符:Windows系统使用 ";" Linux系统使用 ":"
文件名称分隔符:Windows系统使用 "\" Linux系统使用 "/"
*/
public static void main(String[] args) {
// 获系统分隔符
"%SystemRoot%;%JAVA_HOME%\bin";
"%SystemRoot%" + File.pathSeparator + "%JAVA_HOME%" + File.separator + "bin";
}
路径介绍
在日常生活中指的是道路。从起点到终点经过的所有途径。
在网络中,路径指的是从起点到终点的全程路由。比如需要在电脑中查找某个文件,查找的过程中经历的每一个目录的组合,就是当前文件的路径。
在计算机中,路径分为绝对路径 和 相对路径
- 绝对路径:指的是一个完整的路径。它是以盘符(C: D:)开始的路径。
C:\aaa\bbb\ccc\1.txt - 相对路径:是一个简化的路径。相对指的是相对于当前项目的根目录。
如果使用当前项目的根目录,路径可以简化书写:
E:\\ideawork\\javase_XX期\\就业班\\dayXX ----> dayXX(可以省略项目的根目录)
- 路径使用注意事项:
- 路径的书写格式是不区分大小写的
2. 路径中文件名称分隔符Windows使用右斜杠\,反斜杠在java中表示转义符,两个反斜杠代表一个 普通的反斜杠。
- 路径的书写格式是不区分大小写的
1.3 构造方法
目标
- 能够使用File的构造方法创建File对象。
成员方法:
- public File( String pathname ) :通过将给定的路径名字符串转换为抽象路径名来创建新的 File实例。
- public File( String parent, String child ) :从父路径名字符串和子路径名字符串创建新的 File实例。
- public File( File parent, String child ) :从父抽象路径名和子路径名字符串创建新的 File实例。
注意事项:
- File类的构造方法创建File对象时,JVM不会检测当前路径是否存在。File类有专门判断路径是否存在的方法。
- File类的构造方法中,指定的路径可以是绝对路径,也可以是相对路径。
步骤
-
使用File类的各个构造方法创建File对象。
-
通过指定各种不同类型的路径名称创建File对象。
-
打印输出File对象,查看数据变化。
import java.io.File;
/*
演示File类的构造方法:
File(String pathname)
创建一个指定字符串路径的文件对象。
File(String parent, String child)
将指定的字符串父目录和字符串子目录合并,创建一个文件对象。
File(File parent, String child)
将指定的文件父目录和字符串子目录合并,创建一个文件对象。在创建File对象时,不判断路径是否存在,即使不存在也可以正常创建。 在File中有方法来完成文件路径是否存在的判断。 路径可以以文件结尾,也可以以文件夹结尾。 路径可以是绝对路径,也可以是相对路径。 路径的格式: 盘符:/路径/文件; 盘符:\\路径\\文件;
*/
public class FileConstructorDemo {
public static void main(String[] args) {
// File(String pathname) 创建一个指定字符串路径的文件对象。
constructor01();// File(String parent, String child) constructor02( "C:\\abc\\","a.txt"); constructor02( "D:\\abc\\","d.txt"); // File(File parent, String child) constructor03(); } /* File(String pathname) 创建一个指定字符串路径的文件对象。 */ public static void constructor01(){ String pathname = "D:/aaa.txt"; File file = new File( pathname ); System.out.println("file = " + file); } /* File(String parent, String child) 将指定的字符串父目录和字符串子目录合并,创建一个文件对象。 参数:将路径参数分为两部分 String parent; 父路径 String child; 子路径 好处:父路径和子路径,都可以单独书写,使用起来非常灵活,子父路径都可以变化 */ public static void constructor02( String parent, String child ) { File file = new File(parent, child); System.out.println(file); } /* File(File parent, String child) 将指定的文件父目录和字符串子目录合并,创建一个文件对象。 参数:将路径参数分为两部分 File parent; 父路径 String child; 子路径 好处: 1、父路径和子路径,都可以单独书写,使用起来非常灵活,子父路径都可以变化 2、父路径是File类型,可以使用File类的方法对路径进行一些操作,然后在使用路径创建对象 */ public static void constructor03() { // 创建父路径File对象 File parent = new File("D:\\abc"); File file = new File(parent,"HelloWorld.java"); System.out.println("file = " + file); }
}
小结
File的构造方法主要是用于创建File对象。一个File对象代表硬盘中实际存在的一个文件或者目录。无论该路径下是否存在文件或者目录,都不影响File对象的创建。构造方法中指定的路径可以是绝对路径或是相对路径。
1.4 常用方法
1.4.1 获取功能的方法
目标
-
能够使用File类中获取功能的常用方法。
-
public String getAbsolutePath() :返回此File的绝对路径名字符串。
- 获取的是当前File对象的绝对路径,即使指定的路径为相对路径。
-
public String getPath() :获取File对象构造方法中指定的路径。
-
public String getName() :获取File对象构造方法中指定的最后一级目录。
- 最后一级目录可以是文件或是文件夹。
- 文件夹是没有大小概念的,所以不能获取文件夹的大小。
- 如果构造方法中指定的路径是不存在的,则返回的字节数为0。
-
public long length() :获取File对象的字节数。
- 文件夹是没有大小概念的,所以不能获取文件夹的大小。
- 如果构造方法中指定的路径是不存在的,则返回的字节数为0。
步骤
- 创建File文件对象
- 分别调用常用的获取功能的方法
- 输出打印返回的数据结果
实现
import java.io.File;
// 演示File类获取的常用方法
public class FileGetMethodDemo {
/*
public String getAbsolutePath() :返回此File的绝对路径名字符串。
public String getPath() :将此File转换为路径名字符串。
public String getName() :返回由此File表示的文件或目录的名称。
public long length() :返回由此File表示的文件的长度。
*/
public static void main(String[] args) {
method4();
}
/*
public long length() :返回由此File表示的文件的长度。
获取构造方法中传递的文件的大小,以字节为单位
注意:
1、文件夹是没有大小概念的,不能获取文件夹的大小
2、如果构造方法中传递的路径不存在,则length()方法返回0
*/
private static void method4() {
File f1 = new File("E:\\ideawork\\javase_XX期\\就业班\\dayXX\\demo\\abc.txt");
long length1 = f1.length();
System.out.println("length1 = " + length1); // 894
File f2 = new File("E:\\ideawork\\javase_XX期\\就业班\\dayXX\\demo\\123.txt");
long length2 = f2.length();
System.out.println("length2 = " + length2); // 0
}
/*
public String getName() :返回由此File表示的文件或目录的名称。
返回构造方法中传递的路径的最后一级目录。
不管最后一级目录是文件夹 还是 文件都正常返回
*/
private static void method3() {
File f1 = new File("E:\\ideawork\\javase_XX期\\就业班\\dayXX\\1.txt");
String name1 = f1.getName();
System.out.println("name1 = " + name1); // 1.txt
File f2 = new File("E:\\ideawork\\javase_XX期\\就业班\\dayXX");
String name2 = f2.getName();
System.out.println("name2 = " + name2); // day08
}
/*
public String getPath() :将此File转换为路径名字符串。
返回构造方法中传递的路径
如果构造方法中传递的是绝对路径,则返回绝对路径
如果构造方法中传递的是相对路径,则返回相对路径
*/
private static void method2() {
File f1 = new File("E:\\ideawork\\javase_XX期\\就业班\\dayXX\\1.txt");
String path1 = f1.getPath();
System.out.println("path1 = " + path1);
File f2 = new File("1.txt");
String path2 = f2.getPath();
System.out.println("path2 = " + path2); // 1.txt
}
/*
public String getAbsolutePath() :返回此File的绝对路径名字符串。
返回构造方法中传递的路径
不管传递的是绝对路径还是相等路径,最终返回的都是绝对路径
*/
private static void method1() {
File f1 = new File("E:\\ideawork\\javase_XX期\\就业班\\dayXX\\1.txt");
String absolutePath1 = f1.getAbsolutePath();
System.out.println("absolutePath1 = " + absolutePath1);
File f2 = new File("1.txt");
String absolutePath2 = f2.getAbsolutePath();
System.out.println("absolutePath2 = " + absolutePath2);
}
}
小结
File类中的获取方法,主要是获取File对象的各类信息。其他的获取方法请自行查阅API。
1.4.2 判断功能的方法
目标
- 能够使用File类中的判断功能的方法。
- public boolean exists() :此File表示的文件或目录是否实际存在。
- true:表示当前File对象表示的路径是存在的。
- false:表示当前File对象表示的路径是不存在的。
- public boolean isDirectory() :此File表示的是否为目录。
- true:表示当前File对象表示的路径是文件夹。
- false:表示当前File对象表示的路径是文件,或当前路径不存在。
- public boolean isFile() :此File表示的是否为文件。
- true:表示当前File对象表示的路径是文件。
- false:表示当前File对象表示的路径是文件夹,或当前路径不存在。
- 注意事项:
- 在判断某个路径是否为文件或文件夹之前,首先需要判断当前路径是否存在。
- isFile() 和 isDirectory()两个方法为互斥的方法,一个路径的指向,不是文件就是文件夹。
步骤
- 创建File对象,分别指定存在或不存在的路径。
- 调用判断的方法,获取结果并输出打印。
实现
import java.io.File;
// 演示File类判断的常用方法
public class FileMethodDemo {
/*
public boolean exists() :此File表示的文件或目录是否实际存在。
public boolean isDirectory() :此File表示的是否为目录。
public boolean isFile() :此File表示的是否为文件。
*/
public static void main(String[] args) {
method2();
}
/*
public boolean isDirectory() :此File表示的是否为目录。
判断传递的文件是否为文件夹。
是:true
不是: false
public boolean isFile() :此File表示的是否为文件。
判断传递的文件是否为文件。
是:true
不是: false
注意:
1、电脑的硬盘上只有文件 或 文件夹 ,两个方法互斥。
2、两个方法的使用前提是路径必须是真实存在的,否则都返回false
所以在判断是否为文件或文件夹之前,一般要先判断路径是否存在
*/
private static void method2() {
File f1 = new File("E:\\ideawork\\javase_XX\\就业班\\dayXX");
if( f1.exists() ) {
System.out.println( f1.isDirectory()); // true
System.out.println( f1.isFile()); // false
}
File f2 = new File("E:\\ideawork\\javase_XX期\\就业班\\dayXX\\dayXX.iml");
if( f2.exists() ) {
System.out.println( f2.isDirectory() ); // false
System.out.println( f2.isFile()); // true
}
}
/*
public boolean exists() :此File表示的文件或目录是否实际存在。
判断构造方法中传递的路径是否存在。
存在:true
不存在:false
*/
private static void method1() {
File f1 = new File("E:\\ideawork\\javase_XX期\\就业班\\dayXX");
boolean exists1 = f1.exists();
System.out.println("exists1 = " + exists1); // true
File f2 = new File("E:\\123.txt");
boolean exists2 = f2.exists();
System.out.println("exists2 = " + exists2); // false
}
}
小结
File类中判断方法,主要用于判断当前文件路径是否存在,当前路径是文件还是文件夹。其他的判断方法请自行查阅API。
1.4.3 创建删除功能的方法
目标
- 能够使用File类中的创建和删除的方法。
- public boolean createNewFile() :当File对象指定的文件不存在时,创建一个新的空文件。
- 当前方法只能用于文件的创建,不能创建文件夹,也不能操作文件中的数据。
- public boolean delete() :删除由此File表示的文件或目录。
- true:删除成功。
- false:删除失败,或当前路径不存在。或删除的文件夹中包含内容。
- 删除不走回收站,使用需谨慎。
- public boolean mkdir() :创建由此File表示的单级目录。如果文件存在则创建失败。
- public boolean mkdirs() :创建由此File表示的多级目录。如果文件存在则创建失败。
- 当前方法只能创建文件夹,不能创建文件。
步骤
-
创建File对象,分别指定存在或不存在的路径
-
调用File类的创建和删除方法
-
运行程序查看结果
import java.io.File;
import java.io.IOException;// 演示File类创建和删除的方法
public class FileMethodDemo {
/*
public boolean createNewFile() :当且仅当具有该名称的文件尚不存在时,创建一个新的空文件。
public boolean delete() :删除由此File表示的文件或目录。
public boolean mkdir() :创建由此File表示的目录。
public boolean mkdirs() :创建由此File表示的目录,包括任何必需但不存在的父目录。
/
public static void main(String[] args) throws IOException {
method3();
}
/
public boolean delete() :删除由此File表示的文件或目录。
删除构造方法中指定路径的文件 或 文件夹
返回值:
true:文件或文件夹删除成功,返回true
false:文件夹中有内容,不会删除返回false;给定的路径不存在返回false。
注意:
delete方法是从硬盘上直接删除文件或文件夹,不走回收站,删除需谨慎。
*/
private static void method3() {
File f1 = new File(“E:\demo\1.txt”);
boolean d1 = f1.delete();
System.out.println("d1 = " + d1);// 删除的文件夹有内容,无法删除 File f2 = new File("e:\\demo\\aaa"); boolean d2 = f2.delete(); System.out.println("d2 = " + d2); // 删除的路径不存在无法删除 File f3 = new File("e:\\abc"); boolean d3 = f3.delete(); System.out.println("d3 = " + d3); } /* public boolean mkdir() :只能创建单级目录。 public boolean mkdirs() :既可以创建单级目录,也可以创建多级目录。 返回值: true: 路径文件夹不存在,创建文件夹返回true false:路径文件夹存在,不会创建返回false 注意: 此方法只能创建文件,不能创建文件夹 */ private static void method2() { // 创建单级目录 File f1 = new File("E:\\demo\\aaa"); boolean mkdir1 = f1.mkdir(); System.out.println("mkdir1 = " + mkdir1); // 创建多级目录 File f2 = new File("E:\\demo\\aaa\\bbb\\ccc\\ddd"); boolean mkdir2 = f2.mkdirs(); System.out.println("mkdir2 = " + mkdir2); // 创建有后缀名的文件夹。 File f3 = new File("E:\\demo\\aaa.txt"); boolean mkdir3 = f3.mkdirs(); System.out.println("mkdir3 = " + mkdir3); } /* public boolean createNewFile() :创建一个新的空文件。 根据构造方法指定的路径,创建出一个空的文件 返回值: true:路径文本不存在,创建文件,返回true false: 文件存在,不会创建,返回false 注意: 1、此方法只能用来创建文件,不能创建文件夹 2、创建文件的路径必须存在,否则抛出异常 */ private static void method1() throws IOException { // 路径存在 File f1 = new File("E:\\demo\\1.txt"); boolean boo1 = f1.createNewFile(); System.out.println("boo1 = " + boo1); // 路径不存在 File f2 = new File("E:\\demo\\123\\1.txt"); //boolean boo2 = f2.createNewFile(); //System.out.println("boo2 = " + boo2); // 不带后缀名的文件,创建的是文件不是文件夹 File f3 = new File("E:\\demo\\新建文件"); boolean boo3 = f3.createNewFile(); System.out.println("boo3 = " + boo3); }
}
小结
File类中的创建和删除的方法主要是用于创建文件和文件夹,以及删除文件或文件夹。需要注意的是创建文件的方法只能创建文件,而创建文件夹的方法则只能创建文件夹。
1.5 目录的遍历
目标
-
能够完成指定路径的文件夹的遍历。
-
public String[] list() :获取文件夹中每个子文件和子文件夹的字符串名称,保存到String数组中。
-
public File[] listFiles() :获取文件夹中每个子文件和文件夹的File对象,保存到File数组中。
-
特别注意:
- list() 和 listFiles()都是用来遍历目的方法,只是返回的类型不一致。
- 如果指定的文件路径不存在,则会抛出空指针异常。
- 如果指定的文件路径不是文件夹,则会抛出空指针异常。
步骤
- 创建File对象,指定文件夹路径
- 分别调用list() 和 listFiles()方法,获取对应的数据。
- 遍历数组,查看具体的结果
实现
import java.io.File;
import java.io.IOException;
// 演示File类遍历(列举)方法
public class FileMethodDemo {
/*
public String[] list() :返回一个String数组,表示该File目录中的所有子文件或目录。
public File[] listFiles() :返回一个File数组,表示该File目录中的所有的子文件或目录。
注意:
1、list 和 listFiles方法都想用来遍历文件对象的目录 , 返回的数据不同
2、如果当前文件路径不存在,则会抛出空指针异常
3、如果当前文件不是文件夹,也会抛出空指针异常
*/
public static void main(String[] args) throws IOException {
method2();
}
/*
public File[] listFiles() :返回一个File数组,表示该File目录中的所有的子文件或目录。
遍历文件路径下的所有文件,将获取到的文件或文件夹再次封装成文件对象,保存到File数组中并返回
*/
private static void method2() {
File f1 = new File("e:\\demo");
File[] files = f1.listFiles();
for (File file : files) {
System.out.println( file );
}
}
/*
public String[] list() :返回一个String数组,表示该File目录中的所有子文件或目录。
遍历文件路径下的所有文件,获取文件的字符串名称,保存到String数组中并返回
*/
private static void method1() {
File f1 = new File("e:\\demo");
String[] dir = f1.list();
for( String fileName : dir ) {
System.out.println(fileName);
}
// 文件对象不是文件夹 或 路径不存在 抛空指针异常
File f2 = new File("e:\\demo\\0.jpg");
String[] dir2 = f2.list();
for (String s : dir2) {
System.out.println(s);
}
}
}
小结
调用list() 或 listFiles()方法的File对象,表示的必须是实际存在的目录,否则返回null,无法进行遍历。并且指定的目录也必须是文件夹。
第二章 递归
2.1 概述
目标
- 能够理解递归的概念。
在前面学习方法时,我们知道可以通过一个方法调用另外一个方法。而方法本身也可以调用它自己本身。我们将这种现象称为:递归。
-
递归:指在当前方法内调用自己的这种现象。递归分为两种: 直接递归和间接递归。
- 直接递归:表现为方法自身调用自己。
- 间接递归:表现为方法A调用方法B,方法B调用方法A
-
递归注意事项
- 递归一定要有结束的条件限定,保证递归能够停止下来,否则会发生栈内存溢出。
- 即使在有结束条件的限定下,递归的次数也不宜过多,否则也会发生栈内存溢出。
- 构造方法禁止递归。
-
递归的使用前提
当调用方法的时候,方法的主体不变,但是每次调用方法时的参数不同,可以使用递归。
提示
当一个方法调用另外一个方法的时候,被调用的方法如果没有执行完毕,当前方法就会一直等待被调用的方法执行完毕之后,才会继续执行。
步骤
递归演示
- 创建a()方法,在方法内部调用自己本身。
- 执行程序,查看结果。
- 创建a( int i )方法
- 方法内部打印i,然后判断i是否==20000,是则结束程序
- 如果i!=20000,则方法内部调用a(++i);
- 运行程序,查看结果。
实现
// 演示递归异常
public class FileMethodDemo {
/*
递归一定要有结束的条件限定,保证递归能够停止下来,否则会发生栈内存溢出。
即使在有结束条件的限定下,递归的次数也不宜过多,否则也会发生栈内存溢出。
构造方法禁止递归。
递归的使用前提
当调用方法的时候,方法的主体不变,但是每次调用方法时的参数不同,可以使用递归。
*/
public static void main(String[] args) throws IOException {
//a();
a(1);
}
/*
即使在有结束条件的限定下,递归的次数也不宜过多,否则也会发生栈内存溢出。
*/
private static void a( int i ) {
System.out.println( i );
if( i == 20000 ) {
return;
}
a(++i);
}
/*
递归一定要有结束的条件限定,保证递归能够停止下来,否则会发生栈内存溢出。
原因是a方法在栈内存中出现的次数过多,导致栈内存容纳不下。
*/
private static void a() {
a();
}
}
小结
递归指的是方法调用自己本身,分为直接和间接递归。递归在使用时,要有结束的条件。并且递归的次数不能过多。否则都会造成内存的溢出。
2.2 递归累和
目标
- 能够使用递归计算1-n的和值。
步骤
分析:
计算的公式:1 + 2 + 3 ... + n; 也可以被推导为下列公式: n + ( n - 1 ) + ( n - 2 ) + ... + 1;
已知最大值为: n ,最小值为: 1
- 递归的结束条件,就是获取到1的时候结束
2. 递归的目的,就是获取下一个需要被加的数字( n - 1 )
实现步骤:
- 定义sum( int n )方法。
- 判断 n == 1。满足条件则直接return 1;
- 如果 n != 1。 return n + sum( n - 1 );
- 调用方法,传递3并获取返回值运行查看结果。
实现
// 演示递归计算1-n之间的和值。
public class Demo {
public static void main(String[] args) {
int sum = sum(3);
System.out.println("sum = " + sum);
}
// 使用递归计算 1 - n之间的和值
public static int sum( int n ){
// 当获取到1的时候,结束程序
if( n == 1 ) {
return 1;
}
// 当num不为1时,调用sum方法本身,获取下一个被加的数字( n - 1 )
return n + sum(n - 1);
}
}
小结
遇到需求,如果通过其他方式能够完成功能的实现,建议不要使用递归。运行效率比较低。
2.2.1 递归求阶乘
-
阶乘:所有小于及等于该数的正整数的积。
n的阶乘:n! = n * (n-1) … 3 * 2 * 1
分析:这与累和类似,只不过换成了乘法运算,学员可以自己练习,需要注意阶乘值符合int类型的范围。
推理得出:n! = n * (n-1)!
代码实现:
public class DiGuiDemo {
//计算n的阶乘,使用递归完成
public static void main(String[] args) {
int n = 3;
// 调用求阶乘的方法
int value = getValue(n);
// 输出结果
System.out.println("阶乘为:"+ value);
}
/*
通过递归算法实现.
参数列表:int
返回值类型: int
*/
public static int getValue(int n) {
// 1的阶乘为1
if (n == 1) {
return 1;
}
/*
n不为1时,方法返回 n! = n*(n-1)!
递归调用getValue方法
*/
return n * getValue(n - 1);
}
}
2.3 递归打印多级目录
目标
- 能够使用递归完成多级目录的打印。
分析:多级目录的打印,就是当目录的嵌套。需要将指定路径中的所有文件获取。如果获取到的是文件则直接打印,如果获取到的是文件夹则需要继续遍历。
步骤
- 定义printDir( File file )方法。参数为需要遍历的文件对象。
- 调用listFiles()方法获取指定文件中的所有的File对象。
- 遍历获取的File对象数组,取出每个文件对象。
- 调用isDirectory()方法,判断当前获取的文件对象是否为文件夹对象
- 如果是则继续调用printDir()方法,将新获取的文件夹对象传递继续遍历
- 如果不是文件夹对象,则表示一定是文件对象,直接打印当前文件对象。
实现
// 演示递归打印多级目录
public class Demo {
public static void main(String[] args) {
// 创建文件对象
File file = new File("e:\\demo");
printDir( file );
}
// 使用递归的方式,遍历文件目录下的所有文件和子文件,子子文件....
public static void printDir( File file ){
// 获取文件对象内的所有子文件对象
File[] files = file.listFiles();
// 遍历获取文件内的所有子文件对象
for( File dirs : files ) {
// 对获取的文件对象进行判断,如果是文件就打印输出
if( dirs.isFile() ) {
System.out.println(dirs);
} else {
// 进入else说明当前文件对象是文件夹,是文件夹就继续遍历。
printDir( dirs );
}
}
}
}
小结
通过递归可以完成指定文件路径的遍历,需要注意的是,如果获取到的文件对象是文件夹对象,需要重新遍历的是新获取的文件夹对象,而不是原来是文件对象。
第三章 综合案例
3.1 文件搜索
目标
- 能够使用递归获取指定目录中的指定类型的文件。
搜索E:\demo 目录中的.txt 文件。
步骤
- 复制使用前面的案例代码进行扩展。
- 如果判断的结果为文件对象,则继续对文件对象进行处理。
- 获取文件对象的名称
- 因为后缀名不区分大小写,所以将获取的文件名称全部改为小写。以免漏到大写后缀的文件。
- 对小写之后的文件名做判断,是否是以.txt结尾的。如果是则打印。
实现
// 演示递归打印指定类型的文件
public class Demo {
public static void main(String[] args) {
// 创建文件对象
File file = new File("e:\\demo");
printDir( file );
}
// 递归打印指定类型的文件
public static void printDir( File file ){
// 获取文件对象内的所有子文件对象
File[] files = file.listFiles();
// 遍历获取文件内的所有子文件对象
for( File dirs : files ) {
// 对获取的文件对象进行判断,如果是文件就打印输出
if( dirs.isFile() ) { // 判断文件对象是否是文件
/* // 先获取文件对象的String类型的名称
String name = dirs.getName();
//String name1 = dirs.getAbsolutePath();
//String name2 = dirs.getPath();
// 为了防止有的后缀名为大写,导致无法获取,先将文件名称改为全部小写
String s = name.toLowerCase();
// 判断文件名称是否以.txt为结尾
if( s.endsWith(".txt") ) {
System.out.println(dirs);
}*/
// 使用链式编程一步完成
if( dirs.getPath().toLowerCase().endsWith(".txt") ) {
System.out.println(dirs);
}
} else {
// 进入else说明当前文件对象是文件夹,是文件夹就继续遍历。
printDir( dirs );
}
}
}
}
小结
获取到文件对象之后,可以对获取的文件对象进行继续的各类操作。针对于获取指定类型的文件案例,需要特别注意:后缀名是不区分大小写的。所以在获取到文件名之后,需要将文件名全部改为大小或小写,在进行判断。
3.2 文件过滤器优化
- 过滤器:就是把不需要的过滤出去,留下需要的内容。
- 文件或文件夹过滤器:过滤掉不需要的文件或文件夹,留下需要的文件或文件夹。
3.2.1 FileFilter文件过滤器
目标
- 能够使用文件过滤器,过滤指定类型的文件。
在File类中,listFiles()有一个重载的方法,重载方法中传递的参数就是文件过滤器对象。
- java.io.FileFilter: 抽象路径名的文件过滤器。 用来过滤文件。过滤的对象是文件对象。
- 抽象方法:
- boolean accept(File pathname) :用来过滤文件的方法。结果为true则保留。
- File pathname:指定遍历的文件对象中的所有子文件对象。
- boolean accept(File pathname) :用来过滤文件的方法。结果为true则保留。
步骤
- 使用接口实现类的方式完成文件的过滤。
- 创建一个FileFilter接口的实现类。
- 在实现类中重写accept()方法。
- 对参数File pathname进行判断:
- 判断当前文件对象是否为文件夹,如果是则保留继续遍历。
- 如果当前文件对象是文件,则判断是否为指定后缀名的文件。是则打印输出。
- 定义printDir(File file)方法,用于递归。
- 调用listFiles()方法,并传递过滤器实现类对象。
- 对listFiles()返回的File数组进行遍历。是文件夹继续遍历,是文件直接打印输出。
- 分别在使用匿名内部类 和 Lambda表达式实现。
实现
使用自定义实现类代码演示:
// 自定义实现类对象
public class MyFileFilter implements FileFilter {
/*
重写过滤的方法
pathname就是需要过滤的文件对象内的所有子文件对象
如果拿到的是文件对象,需要将后缀名为.txt的文件留下,其他类型的文件过滤掉
如果拿到的是文件夹对象,也需要留下来继续遍历,取出其中的子文件和子子文件
*/
public boolean accept(File pathname) {
// 判断是否为文件夹,如果是则过滤下来,继续遍历
if( pathname.isDirectory() ) {
return true;
}
// 遍历是否是以.txt后缀结尾的文件,如果是过滤下来直接打印
return pathname.getPath().toLowerCase().endsWith(".txt");
}
}
// 演示递归打印指定类型的文件
public class FileFilterDemo {
public static void main(String[] args) {
// 创建文件对象
File file = new File("e:\\demo");
printDir( file );
}
// 递归打印指定类型的文件
public static void printDir( File file ){
// 获取文件对象内的所有子文件对象
File[] files = file.listFiles( new MyFileFilter() );
// 遍历获取文件内的所有子文件对象
for( File dirs : files ) {
// 判断文件对象是否是文件
if( dirs.isFile() ) {
System.out.println(dirs);
} else {
// 进入else说明当前文件对象是文件夹,是文件夹就继续遍历。
printDir( dirs );
}
}
}
}
使用匿名内部类代码演示
public class FileFilterDemo {
public static void main(String[] args) {
// 创建文件对象
File file = new File("e:\\demo");
printDir( file );
}
// 递归打印指定类型的文件
public static void printDir( File file ){
// 获取文件对象内的所有子文件对象
File[] files = file.listFiles( new FileFilter(){
public boolean accept(File pathname) {
/*
1、判断是否为文件夹,如果是则过滤下来,继续遍历
2、判断是否是以.txt后缀结尾的文件,如果是过滤下来直接打印
*/
return pathname.isDirectory() || pathname.getPath().toLowerCase().endsWith(".txt");
}
} );
// 遍历获取文件内的所有子文件对象
for( File dirs : files ) {
// 判断文件对象是否是文件
if( dirs.isFile() ) {
System.out.println( dirs );
} else {
// 进入else说明当前文件对象是文件夹,是文件夹就继续遍历。
printDir( dirs );
}
}
}
}
使用Lambda表达式代码演示
分析:FileFilter是只有一个方法的接口,因此可以用lambda表达式简写。
public class FileFilterDemo {
public static void main(String[] args) {
// 创建文件对象
File file = new File("e:\\demo");
printDir( file );
}
// 递归打印指定类型的文件
public static void printDir( File file ){
// 获取文件对象内的所有子文件对象
File[] files = file.listFiles( pathname ->
pathname.isDirectory() || pathname.getPath().toLowerCase().endsWith(".txt"));
// 遍历获取文件内的所有子文件对象
for( File dirs : files ) {
// 判断文件对象是否是文件
if( dirs.isFile() ) {
System.out.println(dirs);
} else {
// 进入else说明当前文件对象是文件夹,是文件夹就继续遍历。
printDir( dirs );
}
}
}
}
小结
FileFilter是用来过滤指定文件对象的过滤器。在抽象方法accept()方法中规定需要保留的文件即可。
3.2.2 FilenameFilter文件名过滤器
目标
- 能够使用FilenameFilter文件名过滤器过滤指定类型的文件。
- java.io.FilenameFilter:抽象路径名的文件名滤器。 过滤的对象是文件的名称。
- 抽象方法:
- accept(File dir, String name):用来过滤指定文件名的抽象方法。
- File dir:被list()方法过滤的那个文件对象。
- String name:文件对象下,所有子文件的字符串名称。
- accept(File dir, String name):用来过滤指定文件名的抽象方法。
步骤
- 定义printDir(File file),用于递归遍历。
- 调用listFiles()方法,使用Lambda表示式传递FilenameFilter接口对象,重写accept( File dir, String name )方法。
- 因为获取的是需要遍历的文件对象和其所有的子文件的名称,因此需要将其先封装成以个完成的File对象。
- 对封装的完成的File对象进行判断是否为文件夹 和 是否为指定类型的文件。
- 遍历listFiles()返回的File数组,如果是文件则直接打印,如果是文件夹则继续遍历。
实现
public class FileFilterDemo {
public static void main(String[] args) {
// 创建文件对象
File file = new File("e:\\demo");
printDir( file );
}
// 递归打印指定类型的文件
public static void printDir( File file ){
// 获取文件对象内的所有子文件对象
File[] files = file.listFiles( (File dir, String name) ->
/*
File dir:遍历的文件目录
String name: 文件目录下的所有文件名称。
1、先将文件对象和文件名称封装成File对象
2、判断封装的文件对象是文件还是文件夹
如果是文件判断:判断是否以.txt为后缀名的文件
如果是文件夹,则保留继续遍历
*/
new File(dir,name).isDirectory() || name.toLowerCase().endsWith(".txt")
);
// 遍历获取文件内的所有子文件对象
for( File dirs : files ) {
// 判断文件对象是否是文件
if( dirs.isFile() ) {
System.out.println(dirs);
} else {
// 进入else说明当前文件对象是文件夹,是文件夹就继续遍历。
printDir( dirs );
}
}
}
}
小结
FilenameFilter是文件的名称过滤器,它获取的是文件的名称,在操作上没有文件过滤器方便。
3.3 获取电脑中的所有的.java文件
目标
- 能够遍历计算机中所有的目录,并获取后缀名为.java的文件。
- static File[] listRoots() 列出可用的文件系统根。 即获取电脑中的各个盘符。
步骤
- 定义方法printDir( File file ),用于递归遍历。
- 调用listFiles()方法,并使用Lambda表达式传递FileFilter文件过滤器对象。
- 重写accept()方法,过滤需要保留的文件对象
- 对listFiles()方法返回的数组进行遍历。如果是文件直接打印,如果是文件夹则继续遍历。
- 在main方法中使用File类的静态方法listRoots()获取所有的根盘符
- 遍历获取的所有根盘符,传递给printDir()方法进行遍历。
实现
public class Demo {
public static void main(String[] args) {
// 获取所有的根目录
File[] files = File.listRoots();
// 遍历根目录
for( File dir : files ) {
printDir(dir);
}
}
public static void printDir( File file ) {
// 调用listFiles方法,获取文件对象中的所有子文件对象
File[] files = file.listFiles( pathname-> pathname.isDirectory() || pathname.getName().toLowerCase().endsWith(".java") );
/*
因为在系统中,有很多受保护的文件。使用windows系统都无法访问,通过File类是依然
无法访问的,因此会获取到空文件。所以在遍历之前,要确保获取的对象不为null。
在File对象不为null的情况下载进行遍历
*/
if( files != null ) {
// 遍历获取的文件对象
for (File dir : files) {
// 判断获取的文件对象是否为文件夹
if (dir.isDirectory()) {
// 继续遍历
printDir(dir);
} else {
// 是文件直接打印
System.out.println(dir);
}
}
}
}
}
小结
在对通过遍历方法获取的File[]遍历之前,要先判断数组中是否存在null值,否则会抛出空指针异常。