观前提示:本篇博客演示使用的 IDEA 版本为2021.3.3版本,使用的是Java8(又名jdk1.8)
电脑使用的操作系统版本为 Windows 10
目录
文件
什么是文件
文件指的是计算机中存储数据的一种形式,可以包含文本、图像、音频、视频等各种类型的数据。在计算机中,文件通常以磁盘、固态硬盘、U盘等存储设备的形式存在,也可以通过网络进行传输和共享。
保存路径的写法
文件存储在硬盘上,每个文件都有一个具体的保存路径
下图的红框里面就是文件的保存路径
在Windows 上面文件保存的写法: D:\GAME
表示一个文件的具体位置路径, 就可以使用 / 来分割不同的目录级别
/ 正斜杠和 \ 反斜杠
/ 正斜杠, \ 反斜杠
上古时期,操作系统,分割目录,都是使用 /
后来(1981年),微软搞了一个操作系统,叫做 DOS .搞这个系统的时候,
发布之前,产品经理临时更改需求,要求使用 \ 来代替 / 分割路径
发布之后,差评如潮,大家都给差评, 你咋使用 \ 呢?
迫于用户压力,微软重新支持了 / 作为分隔符
后来 Windows 也继承了这样的设定
虽然 正斜杠和反斜杠 都可以使用,但是建议优先使用 正斜杠 /
如果使用 \ 写代码,很不方便
例如:
String path = "D:\cat.jpg";
就容易把 \c 识别成一个转义字符,而不是 \ 本身
盘符
在Windows系统中,可以通过打开"我的电脑"或者"此电脑",查看各分区的盘符
通常情况下,系统盘符为C盘,它包含了Windows操作系统的安装文件、系统文件、启动文件、注册表等重要的系统信息。
D:/game 中的 D 就是系统盘符
系统盘符从 C 开头 只要你分盘分的够多,可以一直分到 Z
这些盘符就是通过"硬盘分区"来的
每个盘符可以是一个单独的硬盘,也可以是若干个盘符对应一个硬盘
但是,却没有见到 A 盘和 B 盘,这是为什么呢?
在古老的计算机时代,使用的存储设备主要是软盘和硬盘。其中,软盘分别插在"A驱动器"和"B驱动器"上,称为"A盘"和"B盘"。而当时,系统安装文件和启动文件等通常存储在软盘中,因此软盘的盘符被设置为A盘和B盘。
随着存储设备的不断发展,如光盘、USB闪存驱动器、云存储等的普及,软盘逐渐退出历史舞台,A盘和B盘的盘符也就没有了实际意义。而现代操作系统中,C盘默认为系统盘,储存着系统文件、启动文件、注册表等重要信息。
总结,A盘和B盘的盘符之所以没有被使用,是因为随着存储设备的发展和技术的进步,它们的作用和地位逐渐被替代和淡化了。
保存路径
路径有两种写法
1.绝对路径:以 c: d: 盘符开头的路径
2.相对路径:以当前所在的目录为基准,以 . 或者 .. 开头(. 有时候省略),找到指定路径
当前所在的目录称为 工作目录,每个程序运行的时候,都有一个工作目录
(在控制台里通过命令行操作的时候,是特别明显的,后来进化到图形化界面工作目录就没那么直观)
WIN + R 输入 cmd(大小写均可)
上图为:默认的工作路径
输入一个d:
可以看到已经切换到了D 盘
工作路径是可以修改的
假设当前的工作路径是 D:/blogTest, 我们要定位到 Test1
定位到这个目录就可以写成 ./Test1 (./ 就表示当前目录)
如果工作目录不同,定位到同一个文件,相对路径写法是不一样的
比如定位到的 Test1 这里
如果工作目录是 d:/ 相对路径就写作 ./blogTest/Test1
如果工作目录是 d:/blogTest 相对路径就写作 ./Test1
如果工作目录是 d:/blogTest/aaa 相对路径就写作 ../Test1(.. 表示当前目录的上一级目录)
如果工作目录是 d:/blogTest/aaa/a11 相对路径就写作 ../../Test1
文件的类型
常见的文件类型有:
- 文本文件:txt、doc、docx、ppt、pdf等。
- 图像文件:jpg、png、bmp、gif等。
- 音频文件:mp3、wav、wma等。
- 视频文件:mp4、avi、mov、wmv等。
- 压缩文件:zip、rar、7z等。
以上这些文件类型,整体可以归纳为两类中
1>文本文件(存的是文本,字符串)(字符串,是由字符构成的,每个字符都是通过一个数字来表示的,这个文本文件里存的数据,一定是合法的字符,都是在你指定字符编码的码表之内的数据)
2>二进制文件(存的是二进制数据,不一定是字符串)(没有任何限制,可以存储任何你想要的数据)
那么随便给你个文件,如何区分是文本文件还是二进制文件呢?
直接用记事本打开
如果乱码就说明是二进制文件
不乱码,说明就是文本
Java对文件的操作
Java 对文件的操作有以下两种
1.针对文件系统的操作(文件的创建,删除,重命名)
2.针对文件内容的操作(文件的读和写)
File
属性
修饰符及类型 | 属性 | 说明 |
static String | pathSeparator | 依赖于系统的路径分隔符,String 类型的表示 |
static char | pathSeparator | 依赖于系统的路径分隔符,char 类型的表示 |
构造方法
签名 | 说明 |
File(File parent, String child) | 根据父目录 + 孩子文件路径,创建一个新的 File 实例 |
File(String pathname) | 根据文件路径创建一个新的 File 实例,路径可以是绝对路径或者 相对路径 |
File(String parent, String child) | 根据父目录 + 孩子文件路径,创建一个新的 File 实例,父目录用 路径表示 |
在 new File 对象的时候,构造方法参数中,可以指定一个路径,此时 File 对象就代表这个路径对应的文件(这个路径,可以是绝对路径,也可以是相对路径)
parent 表示当前文件所在的目录
child 自身的文件名
方法
修饰符及返回 值类型 | 方法签名 | 说明 |
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() | 判断用户是否对文件有可写权限 |
代码案例
import java.io.File;
public class IODemo4 {
public static void main(String[] args) {
File file = new File();
}
}
import java.io.File; 这个包里面的 io
i : input 输入
o : output 输出
针对文件系统的操作
File 方法代码演示
String | getParent() | 返回 File 对象的父目录文件路径 |
String | getName() | 返回 FIle 对象的纯文件名称 |
String | getPath() | 返回 File 对象的文件路径 |
String | getAbsolutePath() | 返回 File 对象的绝对路径 |
String | getCanonicalPath() | 返回 File 对象的修饰过的绝对路径 |
import java.io.File;
import java.io.IOException;
public class IODemo4 {
public static void main(String[] args) throws IOException {
//throws IOException 输入输出异常
File file = new File("d:/blogText.txt");
//1.路径不需要真实存在,2.盘符可以大写也可以小写
System.out.println(file.getName());
System.out.println(file.getParent());
System.out.println(file.getPath());
System.out.println(file.getAbsoluteFile());
System.out.println(file.getCanonicalPath());
}
}
上面是绝对路径的写法
下面演示相对路径
import java.io.File;
import java.io.IOException;
public class IODemo4 {
public static void main(String[] args) throws IOException {
File file = new File("./blogText.txt");
// 这个 ./ 代表在 idea 的工作路径下面运行
System.out.println(file.getName());
System.out.println(file.getParent());
System.out.println(file.getPath());
System.out.println(file.getAbsoluteFile());
System.out.println(file.getCanonicalPath());
}
}
这是我的 idea 工作路径
接着往下看
boolean | exists() | 判断 File 对象描述的文件是否真实存在 |
boolean | isDirectory() | 判断 File 对象代表的文件是否是一个目录 |
boolean | isFile() | 判断 File 对象代表的文件是否是一个普通文件 |
import java.io.File;
public class IODemo5 {
public static void main(String[] args) {
File file = new File("d:/blogText.txt");
System.out.println(file.exists());
System.out.println(file.isFile());
System.out.println(file.isDirectory());
}
}
为什么是 false ,因为我的 D 盘里面没有 bolgText.txt 文件
所以 他的 isFile 是false
exists 也是 false
我们可以使用这个方法创建一个
boolean | createNewFile() | 根据 File 对象,自动创建一个空文件。成功创建后返回 true |
import java.io.File;
import java.io.IOException;
public class IODemo5 {
public static void main(String[] args) throws IOException {
File file = new File("d:/blogText.txt");
file.createNewFile();
System.out.println(file.exists());
System.out.println(file.isFile());
System.out.println(file.isDirectory());
}
}
我们既可以创建,也可以删除
boolean | delete() | 根据 File 对象,删除该文件。成功删除后返回 true |
import java.io.File;
public class IODemo6 {
public static void main(String[] args) {
File file = new File("D:/blogText.txt");
file.delete();
}
}
void | deleteOnExit() | 根据 File 对象,标注文件将被删除,删除动作会到JVM 运行结束时才会进行 |
这个东西,在其他地方演示更加明显
比如,你在桌面创建一个文档
上面这个实的就是创建的文档,当你打开以后再里面输入内容,但是不保存,他还会出现一个虚的,就是下面的
这个就是 word 文档生成的临时文件,这个临时文件,相当于保存了你当前实际编辑的内容(尤其是你还没有保存的时候)
防止你编辑了很多东西,但是还没有保存,突然停电了,蓝屏了,死机了,等等一系列不可抗力事件发生了以后,
他会在你下次启动的时候,提醒你是否要恢复之前的编辑内容
这种功能很多程序都有,就可以使用 deleteOnExit 的方式来删除
boolean | mkdir() | 创建 File 对象代表的目录 |
boolean | mkdirs() | 创建 File 对象代表的目录,如果必要,会创建中间目 录 |
我们也可以使用这个方法来创建一个文件
import java.io.File;
public class IODemo7 {
public static void main(String[] args) {
File dir = new File("test");
dir.mkdir();
}
}
这是运行代码前
运行完,我们得到了这个 test 文件
如果你的没有刷新出来,建议刷新一下
右键就可以得到这个,然后点击蓝色的地方,刷新一下
如果想要创建多级目录就使用 dir.mkdirs
import java.io.File;
public class IODemo7 {
public static void main(String[] args) {
File dir = new File("test/aaa/bbb");
dir.mkdirs();
}
}
我们还可以给 test 改个名字
boolean | renameTo(File dest) | 进行文件改名,也可以视为我们平时的剪切、粘贴操作 |
import java.io.File;
public class IODemo8 {
public static void main(String[] args) {
File file = new File("./test");
File dest = new File("./testBBB");
file.renameTo(dest);
}
}
针对文件内容的操作
针对文件内容,使用"流对象"进行操作,这个"流对象"是一种比喻方式
你想象有一个水龙头,通过这个水龙头进行接水
假设你要接1000ml的水
你可以一次性接完这1000ml
也可以是每次接500ml,分成两次来接完
也可以是每次接100ml,分成十次来接完
你怎么接都可以
这个就是"流对象"
同理,你在想象你有一个羽毛球筒,筒里面有很多羽毛球,但是你每次只能从筒里面取出一个羽毛球
这个就不是"流对象"
你有一个文件,大小为1000个字节
假设你要读取文件里面的1000个字节
你可以一次性读取这1000字节
也可以是每次读取500个字节,分成两次来读完
也可以是每次读取100字节,分成十次来读完
也可以是其他的读取方式
写文件同理
因此就把读写文件,称为"流对象"
这个比喻并非是 Java 独有的,而是操作系统 api 的设定
进一步的各种编程语言,操作文件也是继承了这个概念
Java 标准库的流对象
从类型上分为两个大类
1.字节流:操作二进制数据
InputStream FileInputStream
OutputStream FileOutputStream
2.字符流:操作文本数据
Reader FileReader
Writer FileWriter
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 源码可以看到他是 抽象类,不能直接 new
那么:抽象类和接口的区别是什么?
- 抽象类是一个拥有抽象方法的类,而接口是一组抽象方法的集合,抽象类可以包含方法的定义与实现,而接口只能包含方法的声明,不包含实现。
- 在Java/C#等语言中,每个类只能继承一个父类(单继承),但是可以实现多个接口(多实现)。因此,抽象类通常用于表示类之间的共性,而接口更适用于描述行为的规范。
- 抽象类可以有构造函数,而接口不允许定义构造函数。
- 子类继承抽象类时,必须实现其中的抽象方法,否则子类也必须被定义为抽象类;而子类实现接口时,必须实现接口中所有的方法,否则子类也必须被定义为抽象类。
- 抽象类可以有成员变量和非抽象方法,而接口只能有常量和抽象方法。
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.InputStream;
public class IoDemo9 {
public static void main(String[] args) throws FileNotFoundException {
//创建 InputStream 对象的时候,可以使用绝对路径/相对路径,也可以是 File 对象
InputStream inputStream = new FileInputStream("D:\\blogTest\\test.txt");
}
}
上面代码中的异常是:文件没找到异常
如果要想打开一个文件去读.就需要保证这个文件是存在的
下面我们来进行读操作
read 三个重载
我们可以看到 read() 方法有三个重载
read() 无参数:一次读一个字节
read() 一个参数:把读到的内容填充到参数的这个字节数组中(此处参数是"输出型参数"),返回值是实际读取的字节数
read() 三个参数:和 2 类似,只不过是往数组的一部分区间里尽可能填充
我们可以看一下 read 的源码
read 读取一个字节,按理说应该返回一个 byte 就行了,但是实际上返回的是 int
因为,他除了要表示 byte 里面的 0~255(-128~127)这样的情况之外,还需要表示一个特殊情况, -1
这个情况表示读取文件结束了(读取到文件的末尾)
下面演示的是读文件操作,用的是 read() 无参数,我在文件里面放的是 HelloThere
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
public class IoDemo9 {
public static void main(String[] args) throws IOException {
//创建 InputStream 对象的时候,可以使用绝对路径/相对路径,也可以是 File 对象
InputStream inputStream = new FileInputStream("D:\\blogTest\\test.txt");
while (true) {
//读操作
int b = inputStream.read();
if (b == -1) {
break;
}
System.out.println("" + (byte) b);
}
inputStream.close();
}
}
可以使用 ASCII 表对照查看
也可以用十六进制的方式打印出来
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
public class IoDemo9 {
public static void main(String[] args) throws IOException {
//创建 InputStream 对象的时候,可以使用绝对路径/相对路径,也可以是 File 对象
InputStream inputStream = new FileInputStream("D:\\blogTest\\test.txt");
while (true) {
//读操作
int b = inputStream.read();
if (b == -1) {
break;
}
System.out.printf("%x\n", (byte)b);
}
inputStream.close();
}
}
还可以读取汉字,我在里面放的 "你好"
这是 十六进制的, 你好
下面的链接就是查看字符集编码的网站
修改 IDEA 字符集
注意:我的 idea 字符集全部改过,所以演示的东西可能和你的 idea 实际情况不一样
如果想要修改 idea 的字符集,可以看以下操作
IDEA 右下角可以看到我的字符集是 UTF-8
第一步:File -> Settings
第二步:在搜索栏输入: File Encodings
把右边红框里面的东西改成 UTF-8 然后点击 OK 即可
言归正传:
read() 一个参数 代码演示
我在 test.txt 里面放的是 HelloThere
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
public class IODemo10 {
public static void main(String[] args) throws IOException {
InputStream inputStream = new FileInputStream("D:\\blogTest\\test.txt");
while (true) {
byte[] buffer = new byte[1024];
int len = inputStream.read(buffer);
// 可以看到有多少,多久读完
System.out.println("len " + len);
if (len == -1) {
break;
}
//读取的结果被放到了 byte 数组中
for (int i = 0; i < len; i++) {
System.out.printf("%x \n", buffer[i]);
}
}
}
}
read 的第二个重载,需要调用者准备一个数组
byte[] buffer = new byte[1024];
这里的传参操作,相当于是把刚才准备好的数组,交给 read 方法,让 read 方法内部针对这个数组进行填写(此处参数相当于"输出型参数")
int len = inputStream.read(buffer);
Java 中一般习惯做法,输入的信息作为参数,输出的信息作为返回值,但是也有少数情况下,是使用参数来返回内容的
上面给的数组长度是1024(希望读取的长度),read 会尽可能读取1024个字节,填到数组里面,
但是实际上 ,文件剩余的长度是有限的,如果剩余的长度超过1024,此时1024个字节都会填满,
返回值就是1024,如果剩余长度不足1024,此时有多少就填多少,
read 方法就会返回当前实际读取的长度(实际读取的长度)
假设你要读取的文件长度超过1024,那么第二次读取的数据会覆盖第一次读取的.因此对于文件的基本操作都是,一边读,一边处理,处理好一部分,在处理下一部分
byte[] buffer = new byte[1024];
此处数组的名字为什么要叫做 buffer ?
因为:他不是缓存(cache)
而是缓冲区(buffer)
buffer 存在的意义,就是为了提高 IO 操作的效率
单词 IO 操作,是要访问硬盘 IO设备,单次操作是比较消耗的时间的
如果频繁进行这样的 IO 操作,耗时肯定更多
单次 IO 时间是一定的,如果可以减少 IO 次数,此时就可以提高程序整体的效率
第一个版本的代码,是读一次一个字节.循环次数比较高,read 次数就比较高
第二个版本的代码,是一次读1024个字节,循环次数就降低了很多,read 次数变少了
缓冲区(buffer),就是在缓和了一下冲突,减少冲击的次数
举个例子就是:
你在嗑瓜子,你是选择磕一个瓜子就去一次垃圾桶?
还是选择磕一把瓜子再去一次垃圾桶?
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(刷新)操作,将数据刷到设备中。 |
除了使用 InputStream 来读文件
还可以使用 OutputStream 来写文件
我们可以看到 write() 也是三种重载
我在这里写入 97,98,99,100,这四个 ASCII码
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
public class IODemo11 {
public static void main(String[] args) throws IOException {
OutputStream outputStream = new FileOutputStream("D:\\blogTest\\test.txt");
outputStream.write(97);
outputStream.write(98);
outputStream.write(99);
outputStream.write(100);
outputStream.close();
}
}
运行程序,发现 IDEA 并没有什么变化,我们打开 text.txt 看看
发现得到了abcd
在运行代码之前,我并没有清除原先的 HelloThere,但是当程序运行完,发现只剩下了 abcd
这是因为: 对于 OutputStream 来说,默认情况下,打开一个文件,会先清理文件原有的内容
(所以前面的 HelloThere 被清除了)
如果不想清空,流对象还提供了一个"追加写"对象
通过这个就可以实现不清空文件,把新内容追加写到后面
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.nio.charset.StandardCharsets;
public class IODemo12 {
public static void main(String[] args) throws IOException {
String FileName="D:\\blogTest\\test.txt";
String content = "新增内容";
OutputStream outputStream = new FileOutputStream(FileName,true);
outputStream.write(content.getBytes(StandardCharsets.UTF_8));
outputStream.close();
}
}
运行程序,然后打开 text.txt
input 虽然是输出,但是要注意, input 和output 的方向
是以CPU 为中心,来看待这个方向的
如上图所示
内存更接近 CPU
硬盘离 CPU 更远
以 CPU 为核心
数据 朝着 CPU 的方向流向, 就是输入,所以就把 数据从硬盘到内存,这个过程称为:读,input
数据 远离 CPU 的方向流向, 就是输出,所以就把 数据从硬盘到内存,这个过程称为:写,output
言归正传
outputStream.close();
这里的 close 操作,含义是关闭文件
进程 -> 在内核里,使用PCB, 这样的数据结构来表示进程
一个线程对应一个 PCB
一个进程对应一个 PCB ,也可以对应多个
PCB 中有一个重要属性,文件描述表(相当于一个数组)记录了该进程打开了那些文件
(即使一个进程有多个线程多个 PCB, 也没关系,这些 PCB 共用一个文件描述表)
每次打开文件操作,就会在文件描述符表中,申请一个位置把这个位置信息放进去
每次关闭文件,也就会把这个文件描述符表项给释放掉
问题来了:如果这个 close 操作没有写,会怎么样
如果没有 close, 对应的表项,没有及时释放,虽然 Java 有 GC,GC操作会在回收这个 OutputStream 对象的时候 去完成这个释放操作,但是这个 GC 不一定及时
所以,如果不手动释放,意味着文件描述符表可能很快就被占满了(这个数组不能自动扩容,存在上限)
如果占满了,后面再次打开文件,就会失败
文件描述符表最大长度,不同系统上面不太一样,但是基本就是几百个到几千个左右
小结:
close 一般来说是要执行的
但是如果一个程序这里的文件自始至终都要使用,不关闭也可以
随着进程结束,PCB 销毁了,文件描述符表也就销毁,对应的资源操作系统就被自动回收了
(如果你的文件close 之后,程序立即结束了,你不 close也没事)
那么,一般写代码的时候,怎么样才能确保这个 close 被执行到了呢?
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
public class IODemo11 {
public static void main(String[] args) throws IOException {
OutputStream outputStream = null;
try{
outputStream = new FileOutputStream("D:\\blogTest\\test.txt");
outputStream.write(97);
outputStream.write(98);
outputStream.write(99);
outputStream.write(100);
}finally {
outputStream.close();
}
}
}
这个虽然可以保证执行,但是不够优雅
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
public class IODemo11 {
public static void main(String[] args) throws IOException {
try (OutputStream outputStream = new FileOutputStream("D:\\blogTest\\test.txt")){
outputStream.write(97);
outputStream.write(98);
outputStream.write(99);
outputStream.write(100);
}
}
}
这个写法虽然没有显示的写 close,实际上是会执行的,因为:只要 try 语句块执行完毕,就可以执行自动到 close.这个语法,在Java 中被称为 try with resource
不是随便拿个对象放到 try() 里就能自动释放,得满足一定需求
实现了 Closeable 接口的类才可以放到 try 的() 中被自动关闭
这个接口提供的方法就是 close 方法
字符流
字符流的用法和字节流差不多
字符流读文件代码演示
import java.io.FileReader;
import java.io.IOException;
import java.io.Reader;
public class IODemo13 {
public static void main(String[] args) {
try (Reader reader = new FileReader("D:\\blogTest\\test.txt")) {
while (true) {
int ch = reader.read();
if (ch == -1) {
break;
}
System.out.println(" " + (char) ch);
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
也可以读汉字
字符流 write
字符流写文件代码演示
import java.io.FileWriter;
import java.io.IOException;
import java.io.Writer;
public class IODemo14 {
public static void main(String[] args) {
try(Writer writer = new FileWriter("D:\\blogTest\\test.txt")){
writer.write("Hello There");
} catch (IOException e) {
e.printStackTrace();
}
}
}
writer.write("Hello There");
像这样的写操作,其实是先写到缓冲区的(缓冲区存在很多状态)
写操作执行完,内容可能在缓冲区,还没有真正的进入硬盘
close 操作就会触发缓冲区的刷新(刷新操作就会让缓冲区把内容写到硬盘里面)
除了 close 方法,还可以通过 flush 方法,也能起到刷新缓冲区的效果
import java.io.FileWriter;
import java.io.IOException;
import java.io.Writer;
public class IODemo14 {
public static void main(String[] args) {
try(Writer writer = new FileWriter("D:\\blogTest\\test.txt")){
writer.write("Hello There");
writer.flush();
//手动刷新
} catch (IOException e) {
e.printStackTrace();
}
}
}
本文完,感谢观看,有什么错误和不足的地方请在评论区指出,一起进步,谢谢 !