1.File类
1.1File类的概述和构造方法
- File类介绍
- 它是文件和目录路径名的抽象表示
- 文件和目录是可以通过File类封装成对象的(就是通过把电脑里的路径放到File对象里,然后File对象就可以去操作那个路径的文件或文件夹了,File中封装了操作文件或文件夹的一些方法)
- 对于File而言,其封装的并不是一个真正存在的文件,仅仅是一个路径名而已。它可以是存在的,也可以是不存在的。
- File是在java.io包下的
- File类的构造方法
方法名 | 说明 |
File(String pathname) | 通过将给定的路径名字符串转换为抽象路径名来创建新的 File实例 |
File(String parent, String child) | 从父路径名字符串和子路径名字符串创建新的File实例,一般来说这个父的字符串应该是一个目录 |
File(File parent, String child) | 从父抽象路径名和子路径名字符串创建新的File实例,一般来说这个父的字符串应该是一个目录 |
什么目录呢?就是文件夹目录。
- 使用示例:
package com.liudashuai;
import java.io.File;
public class Demo {
public static void main(String[] args) {
//File(String pathname):通过将给定的路径名字符串转换为抽象路径名来创建新的 File实例。
File f1 = new File("E:\\itcast\\java.txt");
System.out.println(f1);//输出E:\itcast\java.txt
//File(String parent, String child):从父路径名字符串和子路径名字符串创建新的 File实例。
File f2 = new File("E:\\itcast","java.txt");
System.out.println(f2);//输出E:\itcast\java.txt
//File(File parent, String child):从父抽象路径名和子路径名字符串创建新的 File实例。
File f3 = new File("E:\\itcast");
File f4 = new File(f3,"java.txt");
System.out.println(f4);//输出E:\itcast\java.txt
}
}
从上面的代码可以看出:
- 这个File类重写了toString方法
- File类里面的路径可以是不存在的,我运行的时候我电脑的E盘里没有itcase文件夹
- 你new这个File对象的时候,程序并不会去创建相应文件夹和文件,我运行完后电脑的E盘也没有生成文件夹和文件
(总之就是可以把文件路径封装成为一个File对象,不要求路径是否真实存在,路径就是一个字符串而已,把路径字符串封装成对象的方式就是使用File类的构造方法,File类有四个构造方法,这里我们先就学三个。这三个构造方法可以适应不同情况来构造出一个File对象,比如你有一个File对象,你可以用File(File parent, String child)来构造。)
- 注意:public File(String pathname)的pathname可以是绝对路径,也可以是相对路径,绝对路径就是D:……、E:……这样的,相对路径就是:以那个使用的语句所在的java文件的项目目录为起点的,相对项目目录的位置,怎么看项目目录呢?你去找模块位置,然后在模块位置上一级就是项目目录了,怎么看是不是模块目录呢?模块目录右下角会有一个小蓝点的。
相对路径怎么用呢?你看,比如下面的这个f就是用相对路径的,我们的java.txt的位置是E:\IdeaProjects\JavaSE_code\idea_test\src\com\liudashuai\java.txt文件夹下,我们知道相对位置的起点是项目目录,看到图中的模块的位置都是在E:\IdeaProjects\JavaSE_code文件夹下的,所以我们知道这个文件夹就是项目文件夹,所以相对位置直接就可以写:idea_test\ \src\ \com\ \liudashuai\ \ java.txt,这样来匹配 - 还有就是File(String parent, String child)下面这样的结果都是一样的,都是可以的
package com.liudashuai;
import java.io.File;
public class Demo {
public static void main(String[] args) {
//创建一个File对象
File f = new File("idea_test\\src\\","\\com\\liudashuai\\java.txt");
File f1 = new File("idea_test\\src","\\com\\liudashuai\\java.txt");
File f2 = new File("idea_test\\src","com\\liudashuai\\java.txt");
System.out.println(f);//输出idea_test\src\com\liudashuai\java.txt
System.out.println(f1);//输出idea_test\src\com\liudashuai\java.txt
System.out.println(f2);//输出idea_test\src\com\liudashuai\java.txt
}
}
1.2用File类的创建功能
- 方法分类
方法名 | 说明 |
public boolean createNewFile() | 当具有该名称的文件不存在时,创建一个由该抽象路径名命名的新空文件 |
public boolean mkdir() | 创建由此抽象路径名命名的目录 |
public boolean mkdirs() | 创建由此抽象路径名命名的目录,包括任何必需但不存在的父目录。这个方法是创建目录,不是创建文件。 |
用上面的方法可以来创建本File对象对应路径的目录(文件夹)和文件。会在计算机里真的创建一个文件夹或文件的哦。
- createNewFile方法的示例代码
(注意文件目录用两个反斜杠,但是你在计算机里看文件的路径是一个反斜杠。比如,你计算机里有一个文件夹,你看他的属性是这样的E:\itcast,他文件夹、磁盘、文件都是用\来分开的,你在Java里表示那个路径就得写为E:\itcast)
package com.liudashuai;
import java.io.File;
import java.io.IOException;
public class Demo {
public static void main(String[] args) throws IOException {
//需求1:我要在E:\\itcast目录下创建一个文件java.txt
File f1 = new File("E:\\itcast\\java.txt");
System.out.println(f1.createNewFile());//这个方法需要处理异常,这个方法要是成功创建了一个文件,那么这个方法返回就是true,要是没有创建成功,比如,E那个路径已经有java.txt文件了,那么创建就会失败,返回false。要是我E盘没有itcast这个目录的话,就会抛出异常。
}
}
下图是我E盘没有itcast文件夹,所以抛出异常了,所以这个方法只能创建文件,但是不能创建目录,要是没有找到对应的目录就会抛出异常。
然后我去E盘创建了itcast文件夹,但是不创建java.txt文件,执行程序,发现程序里返回true。且E盘的itcast文件夹里面也出现了java.txt文件。
然后我们再执行一遍程序,因为我们前面已经用这段程序创建了文件了,所以这个File对象的路径位置已经有了文件了,那么,这样执行结果是false,并没有生成文件(我们把前面代码生成的java.txt写上文本,看看执行这个程序后,那个文件里是不是还是有文本的,发现执行后那个文件还是有文本,所以并没有产生一个新的文件把那个文件覆盖了,是直接没有生成文件)。
然后我们把那个java.txt文件删了,并把itcast文件夹隐藏,然后再执行上面的代码,发现隐藏的文件,这个File也是能匹配到的,并在这个itcast隐藏文件夹里创建了java.txt文件。程序返回true。
- mkdir方法的示例
package com.liudashuai;
import java.io.File;
public class Demo {
public static void main(String[] args){
//需求2:我要在E:\\itcast目录下创建一个目录JavaSE
File f2 = new File("E:\\itcast\\JavaSE");
System.out.println(f2.mkdir());//不会抛出异常,这个方法可以在对应位置创建文件夹,但是要求E盘的itcast文件夹是存在的。要是那个itcast文件夹存在,且那个位置本来没有JavaSE文件夹,这个方法可以创建文件夹,并返回true,要是那个itcast文件下已经有了JavaSE文件夹了,不会创建文件夹,且返回false,和上面的方法createNewFile方法一样,只是上面创建的是文件,这里是创建文件夹。要是那个E盘下没有itcast文件夹,这个程序返回的就是false,且不创建文件夹。这个方法可以上面的createNewFile都是只能创建File路径的最后的那个文件或文件夹的。但是这个mkdir不会抛出异常,就算itcast文件夹不存在也不会抛出异常。
}
}
- mkdirs方法的示例
package com.liudashuai;
import java.io.File;
public class Demo {
public static void main(String[] args){
//需求3:我要在E:\\itcast目录下创建一个多级目录JavaWEB\\HTML
File f3 = new File("E:\\itcast\\JavaWEB\\HTML");//这个方法可以创建多级目录,就算前面的itcase和JavaWEB都不存在,也行。他会在E盘下创建itcast目录,然后在itcast目录下,创建一个HTML文件夹。同样,要是那个位置的文件夹已经有了就返回false且不创建文件夹,要是那个位置没有这个文件夹的话,就创建文件夹,并返回true。
System.out.println(f3.mkdirs());
}
}
- 注意事项:要是你调用某个路径为……XX.txt的File对象的mkdir方法,结果还是创建了一个文件夹,不是文件。是创建了一个XX.txt文件名的文件夹
package com.liudashuai;
import java.io.File;
import java.io.IOException;
public class Demo {
public static void main(String[] args) throws IOException {
File f4 = new File("E:\\itcast\\javase.txt");
System.out.println(f4.mkdir());//在那个路径创建了一个叫javase.txt的文件夹,且返回true
}
}
要是我们创建文件夹后发现自己写错了,改了一写代码,如下
package com.liudashuai;
import java.io.File;
import java.io.IOException;
public class Demo {
public static void main(String[] args) throws IOException {
File f4 = new File("E:\\itcast\\javase.txt");
// System.out.println(f4.mkdir());
System.out.println(f4.createNewFile());//返回flase,且没有创建文件,为什么呢?因为那个文件位置已经有了一个叫javase.txt的文件夹了,你再创建一个javase.txt的文件,计算机系统不允许,所以创建失败了,返回false。就算你手动创建也不行,计算机操作系统,不允许一个文件夹下有同名的文件或文件夹,就算你文件夹和文件同名也不行(这里说的操作系统看文件名看的东西包括扩展名哦,要是某个位置有一个java.txt的文件夹,且同级目录下有一个java.doc文件是可以的)
}
}
1.3File类判断和获取功能
- 判断功能(抽象路径名就是File对象代表的路径)
方法名 | 说明 |
public boolean isDirectory() | 测试此抽象路径名表示的File是否为目录 |
public boolean isFile() | 测试此抽象路径名表示的File是否为文件 |
public boolean exists() | 测试此抽象路径名表示的File是否存在 |
- 获取功能
方法名 | 说明 |
public String getAbsolutePath() | 返回此抽象路径名的绝对路径名字符串 |
public String getPath() | 将此抽象路径名转换为路径名字符串 |
public String getName() | 返回由此抽象路径名表示的文件或目录的名称 |
public String[] list() | 返回此抽象路径名表示的目录中的文件和目录的名称字符串数组 |
public File[] listFiles() | 返回此抽象路径名表示的目录中的文件和目录的File对象数组 |
- 示例代码
比如那个java.txt的位置是在这里,执行下面的代码,返回的是下面的结果:
package com.liudashuai;
import java.io.File;
public class Demo {
public static void main(String[] args) {
//创建一个File对象
File f = new File("idea_test\\src\\com\\liudashuai\\java.txt");
// public boolean isDirectory():测试此抽象路径名表示的File是否为目录,要是在计算机中那个File封装的路径表示的是一个目录返回就是true,不是就是flase,路径不存在也是false
// public boolean isFile():测试此抽象路径名表示的File是否为文件,要是在计算机中那个File封装的路径表示的是一个文件返回就是true,不是就是flase,路径不存在也是false
// public boolean exists():测试此抽象路径名表示的File是否存在,存在返回true,不存在返回false
System.out.println(f.isDirectory());//false
System.out.println(f.isFile());//true
System.out.println(f.exists());//true
// public String getAbsolutePath():返回此抽象路径名的绝对路径名字符串,返回这个File对象表示路径的绝对路径
// public String getPath():将此抽象路径名转换为路径名字符串,返回这个File里面你new的对应字符串,要是你用File(String pathname)来构造,构造时用的是绝对路径,返回的就是绝对路径,构造时用的是相对路径,返回的就是相对路径。要是你用File(File parent, String child)来构造,返回的就是parent拼接上child的结果,他们两个拼接起来后是绝对路径,返回的就是绝对路径,拼接起来的是相对路径,那么返回的就是相对路径。要是用File(File parent, String child)构造的File对象,返回的就是parent这个File的getPath的结果拼接上child,然后直接返回。
// public String getName():返回由此抽象路径名表示的文件或目录的名称,就是返回那个java.txt,即返回File表示的路径的末部那个文件名或文件夹名
System.out.println(f.getAbsolutePath());//输出:E:\IdeaProjects\JavaSE_code\idea_test\src\com\liudashuai\java.txt
System.out.println(f.getPath());//输出:idea_test\src\com\liudashuai\java.txt
System.out.println(f.getName());//输出:java.txt
System.out.println("--------");
// public String[] list():返回此抽象路径名表示的目录中的文件和目录的名称字符串数组
// public File[] listFiles():返回此抽象路径名表示的目录中的文件和目录的File对象数组
File f2 = new File("E:\\itcast");
String[] strArray = f2.list();//用这个list方法,就得要求,f2是一个文件夹,不是一个文件,要是那个f2是一个文件或是一个不存在的路径,list返回的就是null。list方法是把这个f2目录下的所有文件夹和文件的名字组成一个String数组给返回。如果这个f2的文件夹存在,但是这个文件夹里面没有东西,这个strArray就是一个空的长度为0的数组。即,f2.list()这个方法要是f2是一个空文件夹,返回就是一个空的数组,不是null
for (String str : strArray) {
System.out.println(str);//输出f2表示的目录下的所有文件名字和文件夹的名字
}
System.out.println("--------");
File[] fileArray = f2.listFiles();//这样也是要f2是一个目录,要是f2表示的是文件或是一个不存在的路径,这个listFiles返回的就是null。这个listFiles方法返回的是这个f2目录下,所有的文件和文件夹的File对象。相当于用f2目录下的所有文件和文件夹的绝对路径,去建File对象,然后把这些对象放在数组里面返回。如果这个f2的文件夹存在,但是这个文件夹里面没有东西,这个fileArray就是一个空的长度为0的数组。即,f2.listFiles()这个方法要是f2是一个空文件夹,返回就是一个空的数组,不是null。
for (File file : fileArray) {
System.out.println(file);
}
}
}
1.4File类删除功能
- 方法声明和功能
方法名 | 说明 |
public boolean delete() | 删除由此抽象路径名表示的文件或目录,删除成功返回true,失败返回false |
- 绝对路径和相对路径的区别
- 绝对路径:完整的路径名,不需要任何其他信息就可以定位它所表示的文件。例如:E:\itcast\java.txt
- 相对路径:必须使用取自其他路径名的信息进行解释。例如:myFile\java.txt
- delete方法只能删除文件和空文件夹(即要删除的文件夹里面不能有东西),删除一个有文件或文件夹的文件夹(即,那个文件夹里面有东西),就会返回false。一个不存在的路径的File调用delete,也会返回false。删除文件,那个文件里面有内容,没有关系,可以删除。文件和文件夹同级的位置有东西,也没有关系,可以删除,只要文件夹里面没有东西就行了。
调用方法如下:
package com.liudashuai;
import java.io.File;
public class Demo {
public static void main(String[] args) {
File f = new File("E:\\itcast\\javase.txt");//假设,这个文件里面有内容,但是没有关系,所以下面的删除返回true
System.out.println(f.delete());
File f1=new File("E:\\itcast\\JavaWEB");//假设,这个文件夹里面,有东西,所以下面的删除是false。
System.out.println(f1.delete());
}
}
注意:这个方式的删除不会保存在回收站,是永久删除。所以使用要小心,不要删除重要的数据。
1.5总结
File类主要的方法是,创建文件/文件夹,删除文件/文件夹,判断某个路径是文件夹还是文件,遍历文件夹,获取File的文件名、路径名
2.递归
2.1递归
- 递归的介绍
- 以编程的角度来看,递归指的是方法定义中调用方法本身的现象
- 递归调用一定得有出口,不然就会抛出StateOverflowError异常,这个是一个Error。这个异常的原因是因为当堆栈溢出发生时抛出一个应用程序递归太深。因为你没有出口,然后又是递归,那么方法栈里面,一直放一个新的栈帧,那么肯定是会把栈放满的时候,这样就会抛出这个当栈满的时候,就会抛出这个异常了。
- 递归是方法调用本身,不断地调用本身使慢慢接近出口,然后到达出口后,那个达到出口的那个方法完成了,就是栈顶的那个栈帧出栈,并把结果返回,这样下一个栈顶的栈帧就可以继续执行了,然后这个栈顶的栈帧又完成了,继续完成下一个栈顶的栈帧……,最后把原来调用这个递归方法的方法完成,并返回结果,递归方法就结束了。
- 递归的基本使用
public class DiGuiDemo {
public static void main(String[] args) {
//回顾不死神兔问题,求第20个月兔子的对数
//每个月的兔子对数:1,1,2,3,5,8,...
int[] arr = new int[20];
arr[0] = 1;
arr[1] = 1;
for (int i = 2; i < arr.length; i++) {
arr[i] = arr[i - 1] + arr[i - 2];
}
System.out.println(arr[19]);
System.out.println(f(20));
}
/*
递归解决问题,首先就是要定义一个方法:
定义一个方法f(n):表示第n个月的兔子对数
那么,第n-1个月的兔子对数该如何表示呢?f(n-1)
同理,第n-2个月的兔子对数该如何表示呢?f(n-2)
StackOverflowError:当堆栈溢出发生时抛出一个应用程序递归太深
*/
public static int f(int n) {
if(n==1 || n==2) {
return 1;
} else {
return f(n - 1) + f(n - 2);//你看,调用f的n越来越接近出口。
}
}
}
- 递归的注意事项
- 递归一定要有出口。否则内存溢出
- 递归虽然有出口,但是递归的次数也不宜过多。否则内存溢出。抛出StackOverflowError异常。
2.2递归的例子1
- 问题:求阶乘。
- 案例需求
用递归求5的阶乘,并把结果在控制台输出 - 代码实现
public class DiGuiDemo01 {
public static void main(String[] args) {
//调用方法
int result = jc(5);
//输出结果
System.out.println("5的阶乘是:" + result);
}
//定义一个方法,用于递归求阶乘,参数为一个int类型的变量
public static int jc(int n) {
//在方法内部判断该变量的值是否是1
if(n == 1) {
//是:方法的结果就是1,这个是递归的出口
return 1;
} else {
//不是:返回n*(n-1)!,不是1就继续递归。
return n*jc(n-1);
}
}
}
上面代码的内存模型长这样,看内存模型可以有助于了解递归的实质。当jc(5)方法执行到return n* jc(n-1);时是先去执行jc(n-1)的,这个方法执行完后,返回结果才会把jc(5)出栈,返回jc(5)的结果。然后jc(n-1)就是jc(4),jc(4)进栈,然后也执行return n* jc(n-1);所以jc(3)进栈,……一直到jc(1)执行,就不用继续递归了,返回1,然后去执行,jc(2),因为jc(1)的结果知道了,所以刚才执行到一半的return n* jc(n-1);可以继续执行了,然后返回后,jc(3)也可以继续执行了,……然后最终jc(5)也继续执行,返回结果。递归结束。
2.3递归的例子2
- 需求:递归遍历目录,拿到这个目录下所有文件的路径(包括这个目录下的目录里面的文件)。
- 案例需求
给定一个路径(E:\itcast),通过递归完成遍历该目录下所有内容,并把所有文件的绝对路径输出在控制台 - 代码实现
package com.liudashuai;
import java.io.File;
public class Demo {
public static void main(String[] args) {
//根据给定的路径创建一个File对象
File srcFile = new File("E:\\itcast");
//调用方法
getAllFilePath(srcFile);
}
//定义一个方法,用于获取给定目录下的所有内容
public static void getAllFilePath(File srcFile) {
//获取给定的File目录下所有的文件或者目录的File数组
File[] fileArray = srcFile.listFiles();
//遍历该File数组,得到每一个File对象
if(fileArray != null) {
for(File file : fileArray) {
//判断该File对象是否是目录
if(file.isDirectory()) {
//是:递归调用
getAllFilePath(file);
} else {
//不是:获取绝对路径输出在控制台
System.out.println(file.getAbsolutePath());
}
}
}
}
}
假设E盘有一个itcase的文件夹,这个文件夹下有JavaSE、JavaWeb文件夹和hello.txt文件。且在javaSE文件夹里面有111.txt,222.txt文件,在JavaWeb文件夹里面有hk.txt文件,所以输出结果如下:
结果: