- 博主简介:想进大厂的打工人
- 博主主页:@xyk:
- 所属专栏: JavaEE初阶
在Java中总会用到文件操作,比如从盘符读写文件,按字节和字符进行数据读写,那么你真的认识什么是文件路径吗?平时谈到的“文件”,指的都是硬盘上的文件,文件IO这里也是操作硬盘了,本篇文章将详细讲解如何对文件系统操作,文件内容操作,文件操作需要用到的哪些API~~
JavaEE中的文件操作和IO,之前我们学习的代码,定义个变量,其实就是在内存上申请空间,Mysql中主要是操作硬盘的,文件IO也是操作硬盘!!
硬盘(外存)和内存相比:
速度:内存比硬盘快很多
空间:内存空间比硬盘小
成本:内存比硬盘贵
持久化:内存掉电后数据丢失,外存掉电后数据还在
目录
文章目录
一、认识文件
1.1 树型结构组织 和 目录
1.2 文件路径
二、文本文件vs二进制文件
三、文件系统操作
3.1 光看知识点,跟听天书一样,那么我来举个例子来理解吧:
4.1 文件内容操作
4.2 不带参数的read方法
4.3 write方法写数据
五、 文件查找内容程序练习
5.1 控制台输入要查询的目录和词
5.2 递归的进行目录/文件的遍历
5.3 文件读取
5.4 测试
一、认识文件
我们先来认识狭义上的文件(file)。针对硬盘这种持久化存储的I/O设备,当我们想要进行数据保存时,往往不是保存成一个整体,而是独立成一个个的单位进行保存,这个独立的单位就被抽象成文件的概念,就类似办公桌上的一份份真实的文件一般。
文件除了有数据内容之外,还有一部分信息,例如文件名、文件类型、文件大小等并不作为文件的数据而存在,我们把这部分信息可以视为文件的元信息
1.1 树型结构组织 和 目录
同时,随着文件越来越多,对文件的系统管理也被提上了日程,如何进行文件的组织呢,一种合乎自然的想法出现了,就是按照层级结构进行组织 —— 也就是我们数据结构中学习过的树形结构。这样,一种专门用来存放管理信息的特殊文件诞生了,也就是我们平时所谓文件夹(folder)或者目录(directory)的概念。
1.2 文件路径
这是文件系统上一个文件/目录,具体位置~
目录(专业术语)==文件夹(通俗的说法)
计算机的目录是由层级结构的
可以看到,文件系统,是以树形结构来组织文件和目录的!!N叉树
文件路径:就是从树根节点出发,沿着树杈,一路往下走,到达目标文件,此时这中间经过的内容
Windows都是从“此电脑”起头的
表示路径的时候,可以把“此电脑” 省略,直接从 盘符 开始表示
C:\javacode\java-ee\springDemo
实际表示路径,是通过一个字符串表示,每个目录之间使用 \ 或者 / 来分割
\ 反斜杠 只是在windows中适用,代码中写需要写出 \\ ,需要转义字符的~
/ 斜杠 通常使用这种,推荐使用
从盘符开始,一层一层往下找,这个过程,得到的路径,叫做绝对路径
从给定的某个目录出发,一层一层往下找,这个过程得到的路径,叫做相对路径
一定要明确,基准目录(工作目录) 是什么!!!
假如工作目录是这个,此时找到
相对路径表示,./JavaEE/springDemo
如果工作目录是
要找到
相对路径表示,../2.多线程(基础).md
. 相对路径中,是一个特殊符号,表示当前目录
..也是特殊符号,表示当前目录的上级目录~~
- . . / . . / 代表上一级目录的上一级目录~
关于路径,非常关键~~
相对路径,一定要明确,工作目录是什么
相比之下,绝对路径,就可以理解成,以“此电脑”为工作路径
文件系统上,任何一个文件,对应的路径,是唯一的!!
不会存在,俩个路径相同,但是文件不同的情况!!
Windows上可以认为,路径和文件是一一对应的
路径就相当于一个文件的“身份标识”
二、文本文件vs二进制文件
文本文件,存储的是文本,文本文件的内容都是由ascii字符构成的
对应ascii来说,表示范围0-127
文本文件里存储的数据,就是遵守ascii或者其他字符集编码,所得到的文件!!
本质上存的是字符
二进制文件存储的是二进制数据,则没有任何字符集的限制,存什么都行
简单粗暴的方式:
之间使用记事本来打开某个文件,如果你看到的内容能看懂,就是文本文件
看不懂,乱乱的,就是二进制文件(不仅仅是char类型)
txt,文本文件
.java / .c 也是文本文件
.class 二进制文件
.exe 二进制文件
jpg,MP3二进制文件
三、文件系统操作
Java 中通过 java.io.File 类来对一个文件(包括目录)进行抽象的描述。注意,有 File 对象,并不
代表真实存在该文件。
File对象是硬盘上的一个文件的“抽象”表示~~
文件是存储在硬盘上的,直接通过代码操作硬盘,不太方便
就在内存中创建一个对应的对象,操作这个内存中改的对象,就可以间接的影响到硬盘的文件情况了~~
构造File对象
我们先来看看 File 类中的构造方法和方法
构造方法
签名 | 说明 |
File(File parent, String child) | 根据父目录 + 孩子文件路径,创建一个新的 File 实例 |
File(String pathname) | 根据文件路径创建一个新的 File 实例,路径可以是绝对路径或者 相对路径 |
File(String parent, String child) | 根据父目录 + 孩子文件路径,创建一个新的 File 实例,父目录用 路径表示 |
方法
修饰符及返回 值类型 | 方法签名 | 说明 |
String | getParent() | 返回 File 对象的父目录文件路径 |
String | getName() | 返回 FIle 对象的纯文件名称 |
String | getPath() | 返回 File 对象的文件路径 |
String | getAbsolutePath() | 返回 File 对象的绝对路径 |
String | getCanonicalPath() | 返回 File 对象的修饰过的绝对路径 |
boolean | exists() | 判断 File 对象描述的文件是否真实存在 |
boolean | isDirectory() | 判断 File 对象代表的文件是否是一个目录 |
boolean | isFile() | 判断 File 对象代表的文件是否是一个普通文件 |
boolean | createNewFile() | 根据 File 对象,自动创建一个空文件。成功创建后返 回 true |
boolean | delete() | 根据 File 对象,删除该文件。成功删除后返回 true |
void | deleteOnExit() | 根据 File 对象,标注文件将被删除,删除动作会到 JVM 运行结束时才会进行 |
String[] | list() | 返回 File 对象代表的目录下的所有文件名 |
File[] | listFiles() | 返回 File 对象代表的目录下的所有文件,以 File 对象 表示 |
boolean | mkdir() | 创建 File 对象代表的目录 |
boolean | mkdirs() | 创建 File 对象代表的目录,如果必要,会创建中间目 录 |
boolean | renameTo(File dest) | 进行文件改名,也可以视为我们平时的剪切、粘贴操 作 |
boolean | canRead() | 判断用户是否对文件有可读权限 |
boolean | canWrite() | 判断用户是否对文件有可写权限 |
3.1 光看知识点,跟听天书一样,那么我来举个例子来理解吧:
IDEA工作路径就是项目所在目录
写相对路径,就是以
这一级为基准,来展开的~~
2.
exists() | 判断 File 对象描述的文件是否真实存在 |
isDirectory() | 判断 File 对象代表的文件是否是一个目录 |
isFile() | 判断 File 对象代表的文件是否是一个普通文件 |
3.
mkdir创建 File 对象代表的目录,mkdirs创建 File 对象代表的目录,如果必要,会创建中间目录
4.
list() | 返回 File 对象代表的目录下的所有文件名 |
listFiles() | 返回 File 对象代表的目录下的所有文件,以 File 对象 表示 |
5.
renameTo(File dest) | 进行文件改名,也可以视为我们平时的剪切、粘贴操 作 |
四、文件内容操作
4.1 文件内容操作
有很多类,一组类
针对文本文件,提供了一组类,统称为“字符流”(典型代表,Reader,Writer)读写的基本单位是字符
针对二进制文件,提供了一组类,统称为“字节流”(典型代表,InputStream,OutputStream)读写的基本单位是字节
每种流对象,又分成俩种,
输入的:Reader,InputStream
输出的:Writer,OutputStream
InputStream 概述
抽象类,不能直接实例化!!!
方法
修饰符及 返回值类 型 | 方法签名 | 说明 |
int | read() | 读取一个字节的数据,返回 -1 代表已经完全读完了 |
int | read(byte[] b) | 最多读取 b.length 字节的数据到 b 中,返回实际读到的数 量;-1 代表以及读完了 |
int | read(byte[] b, int off, int len) | 最多读取 len - off 字节的数据到 b 中,放在从 off 开始,返 回实际读到的数量;-1 代表以及读完了 |
void | close() | 关闭字节流 |
FileInputStream 概述
构造方法
签名 | 说明 |
FileInputStream(File file) | 利用 File 构造文件输入流 |
FileInputStream(String name) | 利用文件路径构造文件输入流 |
切记要进行,非常重要!!
文件这里的资源,需要手动释放!!
主要是“文件描述符”,记载了当前线程都打开了哪些文件~~
每次打开一个文件,就会在这个表里,申请到一个位置~
这个表就可以当作一个数组,数组下标就是文件描述符表,数组元素就是这个文件在内核中的结构体的表示~~
之所以能这么写,是因为InputStream实现了一个特定的接口Closeable
try with resources
带有资源的try操作,会在try代码块结束,自动执行close关闭操作
OutputStream 概述
方法
修饰 符及 返回 值类 型 | 方法签名 | 说明 |
void | write(int b) | 写入要给字节的数据 |
void | write(byte[] b) | 将 b 这个字符数组中的数据全部写入 os 中 |
int | write(byte[] b, int off, int len) | 将 b 这个字符数组中从 off 开始的数据写入 os 中,一共写 len 个 |
void | close() | 关闭字节流 |
void | flush() | 重要:我们知道 I/O 的速度是很慢的,所以,大多的 OutputStream 为 了减少设备操作的次数,在写数据的时候都会将数据先暂时写入内存的 一个指定区域里,直到该区域满了或者其他指定条件时才真正将数据写 入设备中,这个区域一般称为缓冲区。但造成一个结果,就是我们写的 数据,很可能会遗留一部分在缓冲区中。需要在最后或者合适的位置, 调用 flush(刷新)操作,将数据刷到设备中。 |
4.2 不带参数的read方法
public static void main(String[] args) {
try(InputStream inputStream = new FileInputStream("./123.txt")) {
int b = 0;
do {
b = inputStream.read();
System.out.println(b);
}while(b != -1);
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
read读到末尾会返回-1
read和write可以一次读写多个字节,使用byte[]表示
4.3 write方法写数据
五、 文件查找内容程序练习
5.1 控制台输入要查询的目录和词
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
//1.先输入一个要搜索的目录
System.out.println("请输入要搜索的根目录:");
File rootDir = new File(scanner.next());
if (!rootDir.isDirectory()){
System.out.println("输入有误,您输入的目录不存在!");
return;
}
//2.让用户输入一个要查询的词
System.out.println("请输入要查询的词:");
String word = scanner.next();
//3.递归的进行目录/文件的遍历
scanDir(rootDir,word);
}
- 根据根目录构造File对象
- 如果这个file对象不是目录或者不存在的话,则说明输入错误,直接返回退出程序
- 如果是目录,输入要关键字
- 调用scanDir方法对目录进行扫描(自己实现)
5.2 递归的进行目录/文件的遍历
private static void scanDir(File rootDir, String word) {
File[] files = rootDir.listFiles();
if (files == null){
//空目录
return;
}
for (File f:files) {
System.out.println("当前搜索到:" + f.getAbsolutePath());
if (f.isFile()){
//普通文件
//打开文件,读取内容,比较关键词
String content = readFile(f);
if (content.contains(word)){
System.out.println(f.getAbsolutePath()+"包含关键字");
}
}else if (f.isDirectory()){
//是目录,进行递归
scanDir(f,word);
}else {
continue;
}
}
}
1.普通文件,打开文件,读取内容,比较关键词
2.是目录,进行递归
3.空目录退出
5.3 文件读取
private static String readFile(File f) {
// 读取文件的整个内容, 返回出来.
// 使用字符流来读取. 由于咱们匹配的是字符串, 此处只能按照字符流处理, 才是有意义的.
StringBuilder stringBuilder = new StringBuilder();
try (Reader reader = new FileReader(f)){
while (true){
int c = reader.read();
if (c == -1){
break;
}
stringBuilder.append((char)c);
}
} catch (IOException e) {
e.printStackTrace();
}
return stringBuilder.toString();
}
读取文件的整个内容, 返回出来.
使用字符流来读取. 由于咱们匹配的是字符串, 此处只能按照字符流处理, 才是有意义的.