Java中的File类初识到初步应用和递归

Java中的File类初识到初步应用

File类的引用:import java.io.File;
(本文所有代码手敲,如有错误请联系我指正)

文件结构示例

假定电脑硬盘E盘中存在一个文件夹,其文件目录结构如下:

-E
	-Demo
		-Java
			HelloWorld.java
			Hello.txt
		-HTML
			-CSS
				HelloCSS.css
			-JavaScript
				HelloJS.js
			-JQuery
		-jar
			-json
				fastjson-1.2.68.jar
			-JUnit4
				junit-4.11.jar
//-Java代表展开的文件夹Java
//+Java代表未展开的文件夹Java(这里不涉及)	
下文所有的代码都以此目录为例

构造方法

	①File(String pathname)
		通过将给定路径名字符串转换为抽象路径名来创建一个新 File 实例。 
	②File(String parent, String child)
		根据 parent 路径名字符串和 child 路径名字符串创建一个新 File 实例。 
	③File(File parent, String child)
		根据 parent 抽象路径名和 child 路径名字符串创建一个新 File 实例。 

示例:

//file1指向E:/Demo/Java
File file1 = new File("E:\\Demo\\Java");
//file2指向E:/Demo/Java
File file2 = new File("E:\\Demo","Java");
//file3指向E:/Demo/Java/HelloWorld.java
File file3 = new File(file2,"HelloWorld.java");

注:构造方法3等价于
	File file3 = new File(file2.getAbsolutePath(),"Helloworld.java");
	File file3 = new File(file1.getAbsolutePath(),"Helloworld.java");
此时是基于构造方法2实现的,原因在于getAbsolutePath()返回的是String类型
getAbsolutePath()方法下文会讲

Java中的File类在实例化时可以指向一个存在的文件也可以指向一个不存在的文件,File类中存在创造文件的方法,所以指向一个不存在的文件也是可行的。

路径的写法

Java中的"\“是转义字符,在Java程序中最常见的换行符”\n"
那么在Java程序中使"\“作为一个普通的无意义的字符就需要以这种方式表示”\\",用转义字符转义它自己
“\\“在Java程序中表示一个普通的字符”\”
同理
“\\\\“在Java程序中表示普通的字符”\\”
“\\\\\\“在Java程序中表示普通的字符”\\\”
以此类推
"\"和“/”的区别?
Windows系统下的路径分隔符是"\",你在电脑文件夹里看路径就会发现路径分隔符是"\"
Linux和Unix下都是用“/”
因为Java是跨平台语言并且Windows中也可以识别"/"
所以推荐用"/"作为路径分隔符
也可以用File.separator获取系统的路径分隔符
“E:”+File.separator+“Demo"等价于(Windows系统下)“E:\Demo”
(本文用”\“作为路径分隔符是应为本人习惯复制粘贴路径,把”\“改成”/“比加一个”\"复杂,懒 d(´ω`) )

常用方法(未列举的请参考API,不难)

1、boolean exists()
检测file对象的路径的指向是否存在
该方法返回一个Boolean类型的数据

File file1 = new File("E:\\Demo\\Java");
File file2 = new File("E:\\Demo\\C++");//上文假设的文件目录中不存在C++
System.out.println(file1.exists());//true
System.out.println(file2.exists());//false
//一般用法
if(file1.exists()){true
	System.out.println("file1存在");
}else {
	System.out.println("file1不存在");
}

输出结果:

true
false
file1存在

2、boolean isFile()
判断file对象的路径指向的是不是一个文件

File file1 = new File("E:\\Demo\\Java");//目录
File file2 = new File("E:\\Demo\\Java\\HelloWorld.java");//文件
System.out.println(file1.isFile());//false
System.out.println(file2.isFile());//true
//常用用法
if(file1.isFile()){//false
	System.out.println("file1是文件");
}else{
	System.out.println("file1不是文件");
}
if(file2.isFile()){//true
	System.out.println("file2是文件");
}else{
	System.out.println("file2不是文件");
}

输出结果

false
true
file1不是文件
file2是文件

3、boolean isDirectory()
判断file对象的路径是否指向一个目录

File file1 = new File("E:\\Demo\\Java");//目录
File file2 = new File("E:\\Demo\\Java\\HelloWorld.java");//文件
System.out.println(file1.isDirectory());//true
System.out.println(file2.isDirectory());//false
//常用用法
if(file1.isisDirectory()){//true
	System.out.println("file1是目录");
}else{
	System.out.println("file1不是目录");
}
if(file2.isisDirectory()){//false
	System.out.println("file2是目录");
}else{
	System.out.println("file2不是目录");
}

输出结果

true
false
file1是目录
file2不是目录

4、boolean createNewFile()
自动创建一个新的file对象指向的空文件当且仅当该文件不存在。

//这里再Java文件夹下创建一个新的文件test.txt
File file = new File("E:\\Demo\\Java\\test.txt");
//test.txt此时在file对象路径指向的位置并不存在
System.out.println("test.txt是否存在:"+file.exists());//false
System.out.println("test.txt是否创建成功:"+file.createNewFile());//true
//常见应用场景:
//创建日志文件(log文件、txt文件等文本文件并用I/O流写入数据)
//此时test.txt已被创建,在硬盘中真实存在
//该方法不会再创建一个test.txt,返回false
System.out.println("test.txt是否存在:"+file.exists());//true
System.out.println("test.txt是否创建成功:"+file.createNewFile());//false

输出结果:

test.txt是否存在:false
test.txt是否创建成功:true
//此时E:/Demo/Java路径下就会多出一个test.txt
test.txt是否存在:true
test.txt是否创建成功:false

5、boolean mkdir() 和 boolean mkdirs()
创建文件夹
区分时注意方法名尾部是否带s,

//不存在的文件夹Mysql
File file1 = new File("E:\\Demo\\Mysql");
//存在的文件夹Java
File file2 = new File("E:\\Demo\\Java");
//不存在的多层文件夹Mysql/CRUD
File file3 = new File("E:\\Demo\\Mysql\\CRUD");
//下面的代码是每一条单独运行的,这里为了方便写在了一起,至于为什么,看下面的结论。
System.out.println(file1.mkdir());//true
System.out.println(file2.mkdir());//false
System.out.println(file3.mkdir());//false
System.out.println(file1.mkdir());//true
System.out.println(file3.mkdirs());//true

输出结果

true
false
false
true

结论

boolean mkdir()boolean mkdirs()
均可以创建不含子文件夹的空文件夹
即路径“E:\\Demo\\Mysql”中仅有Mysql不存在
两个方法都会在文件夹Demo下创建Mysql文件夹

若要创建带子文件夹的非空文件夹则必须用
boolean mkdirs()
该方法会将路径中所有的不存在的文文件夹创建出来
即路径“E:\\Demo\\Mysql\\CRUD”中Mysql\CRUD两级文件夹均不存在
方法会在文件夹Demo下自动创建文件夹Mysql
同时在刚刚创建的文件夹Mysql中创建文件夹CRUD

两个方法的共同特点:
如果指向的文件夹 	存在	则会创建失败	返回false;
		若文件夹 	不存在	创建成功后	返回true。
返回值可直接写在if()

6、boolean delete()
删除路径抽象表示的文件或目录,不可删除不为空的文件夹。

File file1 = new File("E:\\Demo");
File file2 = new File("E:\\Demo\\Java\\HelloWorld.java");
File file3 = new File("E:\\Demo\\HTML\\JQu");
System.out.println(file1.delete());//false
System.out.println(file2.delete());//true
System.out.println(file3.delete());//true

输出结果

false
true
true

结论

boolean delete()
仅可以删除存在的文件和空的文件夹
文章结尾会给出删除非空文件夹的方法

7、String getName()
返回路径名表示的文件或目录的名称。

File file1 = new File("E:\\Demo\\Java");
File file2 = new File("E:\\Demo\\Java\\HelloWorld.java");
File file3 = new File("E:\\Demo\\Java\\HelloJava.txt");//文件不存在
System.out.println(file1.getName());
System.out.println(file2.getName());
System.out.println(file3.getName());

输出结果

Java
HelloWorld.java
HelloJava.txt

结论

getName()方法会返回file对象指向的文件的名称,即使file.exists()false
可以进一步理解为file对象所指向的文件或目录并不需要在磁盘中真实存在

8、String getPath()
得到file对象的抽象路径
(也称相对路径,在Java项目中默认项目存储路径为父路径,学习下文中绝对路径的获取就理解了)

File file1 = new File("E:\\Demo\\Java");
File file2 = new File("E:/Demo/Java");//路径的写法不同于file1
File file3 = new File("E:\\Demo\\Java“,”HelloWorld.java");
File file4 = new File(file1,"Hello.txt");
File file5 = new File("test.txt");
System.out.println(file1.getPath());
System.out.println(file2.getPath());
System.out.println(file3.getPath());
System.out.println(file4.getPath());
System.out.println(file5.getPath());

输出结果

E:\Demo\Java
E:/Demo/Java
E:\Demo\Java\HelloWorld.java
E:\Demo\Java\Hello.txt
test.txt

结论

File在构造时使用的什么路径
getPath()方法就返回什么路径
注意file1和file5的构造路径和输出结果
构造路径时用得是\\输出却是\的原因看前文路径的写法那里

顺带一提,File的源代码中重写了toString()方法

//File源码中的方法
public String toString() {
	return getPath();
}

所以输出file的抽象路径时可以这么写

System.out.println(file);
System.out.println(file.getPath());
//二者等价

9、String getAbsolutePath() 和 File getAbsoluteFile()
绝对路径的相关方法
现假设你的Java工程文件的路径为:F:\JavaProgram\FileStudy
(抽象路径的默认父路径)
该路径下有一个src文件夹并且src下有一个名为"HelloFile.java"的文件

-F
	-JavaProgram
		-FileStudy
			-src
				HelloFile.java
File file1 = new File("HelloFile.java");
File absoluteFile = file1.getAbsoluteFile();
System.out.println("file1的抽象路径为:"+file1.getPath());
System.out.println("file1的绝对路径为:"+file1.getAbsolutePath());
System.out.println("absoulteFile的相对路径为:"+absoluteFile.getPath());

输出结果

file1的相对路径为:HelloFile.java
file1的绝对路径为:F:\JavaProgram\FileStudy\src\HelloFile.java
absoulteFile的相对路径为:F:\JavaProgram\FileStudy\src\HelloFile.java

结论

String getAbsolutePath()返回file的绝对路径
File getAbsoluteFile()返回一个以file的绝对路径构建的file文件
即
File absoluteFile = file1.getAbsoluteFile();
等价于
File absoluteFile = new File(file1.getAbsolutePath());

相对路径和绝对路径各自的优势
相对路径由于默认以Java工程文件夹为父目录,所以Java工程文件的整体移动不会影响使用相对路径指向工程文件夹内的文件或目录的file对象,不用改路径也可以继续运行

绝对路径顾名思义定位准确,精准。缺点就是文件一旦变更位置就需要改代码
(现在如果使用绝对路径一般都将绝对路径放在.xml之类的配置文件中,通过读取配置文件获取路径,更改时只需要改xml中的配置内容,不用在代码中进行大量的修改定位)

10、long length()
如果文件存在会返回文件的大小,若不存在会返回0
单位是字节(Byte)
返回的数据和你邮件→属性看到的文件大小一样
通常会用这个方法再用流操作文件的时候做一个进度条(已完成的百分比)

11、String[] list() 和 File[] listFiles()
返回下一级文件夹中的内容

File file1 = new File("E:\\Demo\\jar");
String[] list = file1.list();
for(String str:list){
	System.out.println(str);
}
System.out.println("----------假装分割线----------");
File[] files = file1.listFiles();
File[] files = file1.listFiles();
for (File file:files){
	System.out.println(file.getPath());
}

输出结果

json
JUnit4
----------假装分割线----------
E:\Demo\jar\json
E:\Demo\jar\JUnit4

结论

String[] list()
返回文件夹下一级的文件的抽象路径构成的String[]数组
只能往下一级,我们可以看到json和JUnit4文件夹下是有内容的
File[] listFiles()
返回以文件下一级中的文件的绝对路径构建的File对象的File[]数组

该方法还可以实现过滤功能:Java File中的过滤器

工具类整理

1、删除文件夹目录下的全部文件:

/**
* 删除一个文件,如果是文件夹则一并删除文件夹内的内容
* @param file
*/
public static void deleteFile(File file){
	//FIle是否正确表示
	if (file.exists()){
		//FIle是文件夹还是文件
		if (file.isDirectory()){
			//获取文件子列表
			File[] files = file.listFiles();
			//判断是否有子文件
			if (files.length==0){
				//没有子文件,删除文件
				file.delete();
			}else {
				//有子文件,用递归继续判断
				for (File file1:files){
					deleteFile(file1);
				}
			}
			//递归结束后这一步文件夹已经是空文件夹,删除该文件夹
			file.delete();
		}else if (file.isFile()){
			//是文件,直接删除
			file.delete();
		}
	}else {
		System.out.println("文件路径错误");
	}
}

2、遍历文件夹里的全部内容

/**
 * 遍历文件夹里的全部内容
 * @param file  欲遍历的文件
 * @param index 前方间隔字符的数量
 */
public static void selectFile(File file,int index){
	if (file.exists()){
		if (file.isDirectory()){
			for (int i=0;i<index;i++){
				System.out.print("  ");
			}
			System.out.println("-"+file.getName());
			//判断是否有子文件
			File[] files = file.listFiles();
			//有子文件,递归调用
			if (files.length!=0){
				index++;
				for (File file1:files){
					selectFile(file1,index);
				}
			}
		}else if(file.isFile()){
			for (int i=0;i<index;i++){
				System.out.print("  ");
			}
			System.out.println(file.getName());
		}
	}else {
		System.out.println("文件不存在");
	}
}

3、复制文件(可复制文件夹,需要用到流,所以拖更( ̄▽ ̄)~*)

关于递归

递归=自己调用自己
经典的斐波那契数列
f(n)=f(n-1)+f(n-2) {n>2,f(0)=0,f(1)=1}
f(0)=0
f(1)=1
f(2)=f(1)+f(0)=1+0=1
f(3)=f(2)+f(1)=1+1=2

上文中的常用工具类均用到了递归
很多人在使用递归时思路会乱,我分享一下我的思路

以遍历文件夹为例
我们在电脑中查看文件夹的正常思路就是一级一级的翻开
一个可以展开的文件夹全部展开再去翻下一个
所以我们做的事情就是
1、拿到手一个文件,看是文件还是目录
2、是目录就进入它的下一级看,是文件就看一眼进入下一步
程序表示:

public static void selectFile(File file){
    if (file.exists()){
        if (file.isDirectory()){
            File[] files = file.listFiles();
            for (File f:files){
                //进入下一级
            }
        }else if (file.isFile()){
            System.out.println(file.getName());
        }else {
            System.out.println("有毛病");
        }
    }
}

进入下一级也是重复这一轮操作,正好这个方法就能实现这些操作,所以在进入下一级那里调用自己,正好还能传递参数
所以程序就变成

public static void selectFile(File file){
   if (file.exists()){
        if (file.isDirectory()){
        	//输出文件夹名字
        	System.out.println(file.getName());
        	//Point1
            File[] files = file.listFiles();
            for (File f:files){
                //进入下一级
                //Point2
                selectFile(f);
            }
        }else if (file.isFile()){
        	//输出文件名字
            System.out.println(file.getName());
        }else {
            System.out.println("不是目录也不是文件那还能是啥呢?有什么错误");
        }
    }
}

这样就完成递归调用并且可以遍历文件夹了
进一步详解

Point1处有

File[] files = file.listFiles();

之前讲listFiles()方法是说过,这个方法会把下一级的内容整理成File[]返回给你,这就相当于你双击文件夹进去看见了文件夹里面的内容并且可以操作所有你看见的内容。

在Point2处使用了for-each遍历了Point1处得到的File[]数组files
这样就可以对每一个数组中的file进行操作

有些人会在Point2处的递归调用处陷入混乱,此时我建议你把Point2处的递归调用看成另一个方法,这个方法会替你完成下一级的所有工作,这样你就不用考虑太多。
好比斐波那契数列f(4)的值:
f(4)=f(3)+f(2)
计算时肯定优先想到的是f(3)的值和f(2)的值相加而不是把f(3)f和(2)的表达式进一步展开,那样就变成了
f(4)=f(1)+f(0)+f(1)+f(1)+(0)
自找麻烦

都看到这了不给个赞吗?

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值