️ 主页:小夜时雨
️ 专栏:javaEE初阶
️ 如何优雅的活着,是我找寻的方向
我们平时谈到的"文件"(file),指的都是硬盘上的文件
- 速度:内存比硬盘快很多,几千倍的关系
- 空间:内存空间比硬盘小
- 成本:内存比硬盘贵
- 数据的持久化:内存掉电后数据会丢失。硬盘掉电后数据一直存在。
对文件的系统管理,就是按照层级结构进行组织 —— 也就是我们数据结构中学习过的树形结构。这样,一种专门用来存放管理信息的特殊文件诞生了,也就是我们平时所谓文件夹(folder)或者目录(directory)的概
念。
- 从盘符开始,一层一层往下找直到目标文件,寻找过程得到的路径就叫做 绝对路径
- 从给定的某个目录出发(工作目录 / 基准目录),一层一层往下找直到目标文件,这个过程得到的路径就是相对路径。
- 所以一定要明确好基准目录 / 工作目录
- 相对路径中 ./ 表示当前路径 ,两个点加 / 表示当前目录的上一级目录
- 文本文件 存储是文本,内容都是有ascii字符或者其他字符集编码构成的,也就是说文件里存储的数据,就是遵守 ascii 或者其他字符集编码所得到的文件
- 二进制文件 存储的是二进制数据,则没有任何字符集的限制
- 简单的一种判定方式:直接用记事本打开(是按照文本的方式来解析显示的),如果能看懂就是文本文件,看不懂乱码,则就是二进制文件。
二进制都是一个一个的字节,记事本尝试把当前若干个字节的数据往 utf8 码表里套,套出来是啥就是啥,套不出来的就是方块
- 文本文件:.txt .java .c
- 二进制文件: .class .exe .jpg .mp3 以及word编辑的docx 和 excel 编辑的表格
本段内容中,我们主要涉及文件的元信息、路径的操作,暂时不涉及关于文件中内容的读写操作。
java标准库中,给我们提供了File这个类,File对象是硬盘上的一个文件的"抽象"表示,文件是存储在硬盘上的,直接通过代码操作硬盘不太方便,就在内存中创建了一个对应的对象,操作这个内存中的对象,就可以间接影响到硬盘上的文件情况了~~
构造的过程中可以使用绝对路径 / 相对路径 进行初始化,这个路径指向的文件可以是真实存在的,也可以是不存在的 ,下图是构造方法:
2. File提供的方法
方法:
修饰符及返回值类型 | 方法签名 | 说明 |
---|---|---|
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() | 关闭字节流 |
关闭文件操作,释放文件资源(文件描述符表)十分重要,不然会造成文件资源泄露,非常严重的后果
所以我们采用 try (InputStream is = new FileInputStream(“hello.txt”)) { } 这样的代码
InputStream 实现了一个特定的接口Closeable , 带有资源的 try 操作,会在 try 代码块结束后,自动执行 close 操作,以防止后面忘记写 关闭文件操作 (close() )或者中间出现了异常,导致执行不到关闭文件操作 (close() )
InputStream 只是一个抽象类,要使用还需要具体的实现类。关于 InputStream 的实现类有很多,基本
可以认为不同的输入设备都可以对应一个 InputStream 类,我们现在只关心从文件中读取,所以使用 FileInputStream
import java.io.*;
// 需要先在项目目录下准备好一个 hello.txt 的文件,里面填充 "Hello" 的内容
public class Main {
public static void main(String[] args) throws IOException {
try (InputStream is = new FileInputStream("hello.txt")) {
while (true) {
int b = is.read();
if (b == -1) {
// 代表文件已经全部读完
break;
}
System.out.printf("%c", b);
}
}
}
}
对字符类型直接使用 InputStream 进行读取是非常麻烦且困难的,所以,我们使用一种我们之前比较熟悉的类来完成该工作,就是 Scanner 类
import java.io.*;
import java.util.*;
// 需要先在项目目录下准备好一个 hello.txt 的文件,里面填充 "你好中国" 的内容
public class Main {
public static void main(String[] args) throws IOException {
try (InputStream is = new FileInputStream("hello.txt")) {
try (Scanner scanner = new Scanner(is, "UTF-8")) {
while (scanner.hasNext()) {
String s = scanner.next();
System.out.print(s);
}
}
}
}
}
方法
修饰符及返回值类型 | 方法签名 | 说明 |
---|---|---|
void | write(int b) | 读取一个字节的数据,返回 -1 代表已经完全读完了 |
void | write(byte[] b) | 将 b 这个字符数组中的数据全部写入 os 中 |
int | write(byte[] b, int off,int len) | 最多读取 len - off 字节的数据到 b 中,放在从 off 开始,返回实际读到的数量;-1 代表以及读完了 |
void | close() | 关闭字节流 |
void | flush() | 重要:我们知道 I/O 的速度是很慢的,所以,大多的 OutputStream 为了减少设备操作的次数,在写数据的时候都会将数据先暂时写入内存的一个指定区域里,直到该区域满了或者其他指定条件时才真正将数据写入设备中,这个区域一般称为缓冲区。但造成一个结果,就是我们写的数据,很可能会遗留一部分在缓冲区中。需要在最后或者合适的位置,调用 flush(刷新)操作,将数据刷到设备中。 |
代码示例:
import java.io.*;
public class Main {
public static void main(String[] args) throws IOException {
try (OutputStream os = new FileOutputStream("output.txt")) {
os.write('H');
os.write('e');
os.write('l');
os.write('l');
os.write('o');
// 不要忘记 flush
os.flush();
}
}
}
读取的基本单位是字符
try (Reader reader = new FileReader("d:/test.txt") ){ }
try (Writer writer = new FileWriter("d:/test.txt") ) { }
代码示例:
public class IODemo8Reader {
public static void main(String[] args) {
//Reader 和 writer 读写的是文本文件,提供了一组类,统称为“字符流”
try(Reader reader = new FileReader("d:/test.txt")) {
while(true) {
int c = reader.read(); //转成ascii码
if(-1 == c) {
break;
}
System.out.println(c);
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
️️️ 好啦,到这里有关 文件操作和 IO 的分享就没了,如果感觉做的还不错的话可以点个赞,关注一下,你的支持就是我继续下去的动力,蟹蟹大家了,我们下期再见,拜拜~ ☆*: .。. o(≧▽≦)o .。.:*☆