文章目录
- 1.文件初识
- 2.java针对于文件的操作
- 2.1文件系统的操作---file类
- 2.2文件内容的操作---流对象的分类
- 2.4字符流的操作===》文本文件
- 2.4.1异常的说明
- 2.4.2第一种文件内容的读取方式
- 2.4.3第二种读取方式
- 2.4.4close的方法的介绍
- 2.4.5close的使用优化操作
- 2.4.6内容的写入
- 2.3字节流的操作===》二进制文件
- 2.4一些其他的读取方式
- 2.5字节流字符流转换
- 3.练习程序:扫描指定的目录
1.文件初识
我们通常情况下说的这个文件:指的是这个硬盘数据的一个载体,就是硬盘里面的数据;
机械硬盘:擅长顺序读写;
固态硬盘:里面是集成度很高的芯片,效率比机械硬盘高很多;
我们还需要了解诸如这个路径,绝对路径相对录得等相关的知识;
2.java针对于文件的操作
2.1文件系统的操作—file类
pathSeparator----文件的路径的分隔符号;
在我们的这个windows上面,其实无论是正斜杠还是反斜杠这个都是可以作为我们的路径分隔符的;
File对象表示的就是这个硬盘上面的文件,在进行这个对象的构造的时候,需要把这个文件的路径作为参数进行指定;
下面的这个展示的就是我们的这个新创建的这个对象里面的这个对应的可以使用的一些方法:
getpath就是获取这个文件的路径;
getname就是获取这个文件的名字;
getcanonicalpath就是对于这个绝对的路径进行简化;
getparent就是获取这个文件的父目录,也就是这个文件的上一层目录结构;
上面的这个案例可能还看不出来这个getcanonicalPath方法和这个getpath的区别,好像就是把这个盘符的小写变成了大写的,下面的这个例子其实也是为了让我们明白两者的区别,这个getCanonicalPath实际上是针对于这个绝对的路径进行了简化:
因为我们可以看到这个绝对路径和我们的这个最后一个方法的打印结果相比,就是对了一个.,但是这个.的存在其实是可有可无的,因此可以理解为这个getCanonical方法就是对于这个绝对路径获取结果的一个简化的操作;
查看这个文件是不是存在的;
查看这个文件是不是一个目录结构;
查看这个是不是一个文件;
如果上面查看的这个文件是不存在的,买这个时候我们就可以使用这个create的方法去创建一个新的文件,然后再次去检查,这个时候这个文件就是存在的;
下面的这个是针对于文件的删除的操作:delete就是立即删除,onexit就是等待这个进程结束之后再删除;
就是这个我们日常使用的这个office进行这个文档的撰写或者是这个ppt,word之类的这个制作的时候,我们的这个对应的文档的存放的位置实际上会产生一个临时文件的,这个文件的原理就是为了防止突然的断电导致这个文件内容的丢失,但是因为现在的这个笔记本都是电池,因此这个在我们的这个笔记本上面,显示不出来效果;
但是我们打开这个隐藏文件的选项,实际上是可以看到这个隐藏的文件的
下面的这个是使用的这个list方法查看这个目录下面的这个所有的文件内容,返回值是一个字符串的数组,我们如果直接打印,打印的结果是哈希值,需要使用这个toString方法对于这个进行转换之后打印输出;
创建目录的方法:我们可以使用这个mkdir创建指定的这个目录,我们也可以使用这个mkdirs创建多个层级结构的目录;
2.2文件内容的操作—流对象的分类
字符流:对应的文件是我们的文本文件,本质上是针对于这个字节流进行了封装,字符流实际上就是把这个文本文件里面的这个相邻的字节,转换为一个字符;
字节流:对应的文件是我们的二进制文件;
2.4字符流的操作===》文本文件
这个字符流主要是针对于这个文本文件,这个里面主要就是了解这个reader和writer两个类创建的这个对象里面可以进行调用的方法;
2.4.1异常的说明
下面的这个首先是想要对于这个对象的创建过程中出现的异常进行说明,就是我们的这个reader实际上是一个抽象类,因此我们使用这个类去创建对象的时候是不可以直接new对象的,因此我们使用这个new FileReader的方法去创建这个对应的对象,但是这个对象的创建过程中会抛出异常,就是下面的这个第一张图片里面出现的这个filenotfoundexception的异常;
但是我们使用这个对象的方法去调用这个read方法从这个文件里面读取数据内容的时候,这个方法调用的时候也是会抛出来异常的,这个就是我们的IOexception就是输入输出异常;
这个时候我们的这个异常的抛出之后就会把之前的这个filenotfound的这个异常给改掉,其实这个是没有任何的影响的,这个主要就是因为我们的这个异常是上一次抛出的这个异常的父类,两者之间是有这个类的继承关系的;
2.4.2第一种文件内容的读取方式
下面的这个就是我们使用我们创建的reader进行这个文件的内容的读取,为什么这个reader的方法的这个返回值是这个int类型的数据,这个主要是编码和其他的一些原因;
java的这个字符流里面其实使用的是这个unicode编码的方式,这个编码方式的编码的范围就是0~65535大小,而一个char类型的字符正好是65535的大小,可以容纳这个unicode的编码值,但是我们使用这个int类型这个更宽的字符进行处理的时候,我们使用这个-1进行这个特殊情况的表示—就是我们的这个读取的过程结束了,因此这个使用int作为我们的这个方法的返回值也是出于这个特殊值的一个考量;
我们使用这个while进行控制,这个n记录的就是我们的这个读取的字符的个数,当我们读取到这个文件的末尾的时候,这个读取的过程就会结束,然后把我们的读取的内容每一次读取之后都需要进行输出的操作;
2.4.3第二种读取方式
其实说成是这个第二种读取方式也不是很合适,就是这个方法里面多加了参数,也就是我们的这个字符数组,我们把这个读取的内容存放到这个字符数组里面去,然后就可以最后对于这个字符数组进行循环遍历,然后把我们的这个字符数组里面的这个内容进行打印输出;
这个还是使用这个-1进行控制,控制我们的这个程序的结束,也就是这个时候已经读取到了这个文件内容的末尾;
2.4.4close的方法的介绍
这个close其实就是释放资源,这个是最直观的理解,这个具体是什么资源,其实就是我们的这个pcb里面的这个文件描述符表;
我们之前介绍过这个:每一个进程都是用这个PCB内核和我们的代码程序,而且这个进程是系统文件资源分配的基本单位;
文件描述符表:实际上是一个顺序表(数组)–但是这个数组的长度是有限的;我们每一次打开一个文件进行读取,这个表就会被分配一个数据元素,但是这个表的长度有限,当这个表全部被填满的时候,就会出现意想不到的情况,但是这个情况的发生实际上不是我们可以预想到的,因为这个实际上就是需要一定的过程对于这个文件描述符表进行填充的,因此我们使用完成,或者是读取结束的时候,需要关闭这个系统的文件的资源,防止出现上面的这个文件描述符表被填满的情况;
结合上面的这个解释,其实这个close就是对于这个文件描述符表进行释放的;
下面的这个就是我们在这个文件资源的读取结束的时候,加上这个reader.close方法对于这个系统的资源进行关闭,释放我们的这个进程占据的这个文件描述符表里面的这个资源;
2.4.5close的使用优化操作
上面的这个方法固然可以解决问题,但是这个方法还是存在问题的,我们需要对于上面的这个写法进行优化;
因为我们上面的这个对于文件里面的内容进行读取的时候,肯呢个会抛出异常,这个时候一旦抛出,这个进程就会被终止,因此这个时候就会退出程序,不会执行到我们下面的这个close方法的地方;
因此我们可以使用这个try-finally语句把这个异常抛出之后,还会执行到这个close方法的地方,因为我们的这个fanally里面的这个代码块的内容是一定会被执行的;
上面的这个方式不够优雅,我们还是可以继续进行优化操作的:
下面的这个try语句里面的这个写法就是有这个对象的创建,这个写法就是try with resource语法,这个好处就是我们的这个try里面的这个语句块的内容执行完毕的时候,这个就会自动进行这个close的操作;
但是上面的这个写法的要求就是我们的这个try后面的这个括号里面的这个参数就是需要实现我们的这个closeable接口,我们可以向底层追,可以看到这个Reader就是实现了这个closeable接口的;
2.4.6内容的写入
下面的这个创建的writer就是负责向我们指定这个文件里面去写入数据内容,写入到我们的这个指定的文件里面去,这个过程中需要进行异常的处理;
我们的这个write方法写入的时候会把之前的内容覆盖掉,因此我们可以加上这个true参数让这个写入的内容从文件的末尾开始书写;
下面的这个实际上就是在这个构造方法里面添加新的参数,这样就是进行的追加操作,而不会覆盖我们的文件里面已经存在的内容;
2.3字节流的操作===》二进制文件
对于这个字节流里面的这个数据的读取,我们的这个方法的参数是一个byte类型的数组,因此我们需要首先对于这个byte类型的数组进行创建;
下面的这个和上面的字符流的读取其实没有很大的区别:还是创建字符流对象,因为这个inputstream.read调用方法这个这个参数是bute类型的数组,因此我们时候选需要创建符合类型的这个数组;
把这个读取的内容放到这个buffer数组里面去,然后进行打印出来,这个地方是使用的16进制的形式进行的打印输出;
上面的这个是把这个文件里面的这个内容进行读取;下面的这个是OutputStream就是对于这个文件写入内容,我们使用的是这个write方法,但是可以看到这个方法的参数是int或者是这个byte类型的数组,因此我们无法直接把这个str字符串进行输出,而是需要进行类型的转换;
2.4一些其他的读取方式
这个里面的就是我们非常熟悉的scanner类和对象的相关的操作;
我们之前使用的这个scanner类创建的对象用来在这个屏幕上面进行输入,这个参数是这个system.in,这个参数其实就是我们的InputerStream这个类里面的;
下面的这个就是使用的这个scanner,只不过把这个参数换成我们自己创建的这个inputStream对象,这个时候我们的这个scanner就是从文件里面进行读取,而不是从这个输入框里面进行读取;
这个里面也是可以使用这个next方法对于这个文件后续的内容进行读取的;
2.5字节流字符流转换
下面的这个就是通过这个PrintStream这个类进行我们的字节流字符流之间的相互转换,然后向这个文件里面写入数据,这个可能会出现写入的内容积攒在这个缓冲区上面,因此我们需要进行写入之后使用这个flush方法进行刷新,这样我们才可以在我们的这个文件里面看到我们写入的内容;
3.练习程序:扫描指定的目录
制定扫描的目录,找到这个名称里面包含指定字符的文件,询问用户是否需要进行删除这个文件;
分析:其实就是让用户输入一个路径,我们对于这个路径里面的所有的文件一层一层的进行遍历,然后输入这个字符串,看看遍历的过程中这个路径对应的这个文件是不是包含我们的字符串,询问用户是不是进行删除;
1.列举目录下面的内容;
2.判断这个文件的类型;
3.确定是否进行删除;
4.scanDir用于对于这个指定的路径进行扫描,这个路径必须要是一个目录,这个时候我们需要进行判断;
5.checkDelete方法是查看这个文件的名称里面有没有我们的这个指定的字符串
package demo12;import java.io.File;
import java.util.Scanner;public class Test {public static void main(String[] args) {Scanner scanner=new Scanner(System.in);System.out.println("请输入想要扫描的路径:");String path=scanner.next();File rootPath = new File(path);//下面的这个是对于用户可能输入的异常的方法进行判断的if(!rootPath.isDirectory()){System.out.println("你输入的这个路径不正确");return;}System.out.println("请输入你想要查询的关键词");String word = scanner.next();scanDir(rootPath,word);}
@SuppressWarnings({"all"})private static void scanDir(File rootPath,String word){//1.列举出来这个目录下面的所有内容File[] files = rootPath.listFiles();if(files==null){return;}//下面的这个是使用的增强for的方法进行遍历的for(File f:files){System.out.println("当前扫描的这个文件就是:"+f.getAbsolutePath());if(f.isFile()){//查看这个目录名称上面是不是我们的这个单词,封装一个新的方法checkDelete(f,word);}else{//下面的这个实际上就是针对于我们的这个遍历的每一个元素// 再次调用这个方法去进行判断//这个其实就是一个不断的递归的过程scanDir(f,word);}}}
@SuppressWarnings({"all"})private static void checkDelete(File f,String word){if(!f.getName().contains(word)){//前面加上了!说明没有包含这个word我们直接返回即可return;}//打印日志:当前的这个遍历到的文件的具体的路径System.out.println("当前的这个文件是:"+f.getAbsolutePath()+"请确认是否需要删除");Scanner scanner = new Scanner(System.in);String choice = scanner.next();//这个说明用户是yes的,即我们可以进行删除if(choice.equals("Y")||choice.equals("y")){f.delete();System.out.println("删除完毕");}//只要是用户输入的其他内容,我们就不会进行删除else{System.out.println("取消删除");}}
}``