一、画图分析
其实也不难,就是多了一个缓冲区而已。
在输出的时候首先要有一个目的地,假设编码规则还是 UTF-8
,现在我要利用字符输出流,将数据写到文件中。
当我们创建字符输出流(FileWriter
)对象的时候,那就好比内存跟文件之间有了这么一个连接通道。
与此同时在创建 FileWriter对象
的时候,也创建了一个长度为 8192的字节数组
,其实就是我们刚刚所说的缓冲区。
![image-20240503172801860](https://img-blog.csdnimg.cn/img_convert/dfea53dfaf8d455bb893cf8f551fe166.png)
接下来会用下面的代码去写出数据。
在写出的时候它会把所有的数据按照 UTF-8
进行编码,一个中文变成三个字节,一个英文变成一个字节。
在写的时候跟字节流是不一样的,字节流没有缓冲区,它是直接写到文件的目的地的。
但是字符流是有缓冲区的,它是先写到缓冲区中。
![image-20240503173034985](https://img-blog.csdnimg.cn/img_convert/8df105642758c2e519540cdf1956c32e.png)
那数据什么时候才能真正的保存到目的地呢?有三种情况。
情况1:缓冲区装满了,它会自动保存到目的地,不需要我们进行任何的操作。
情况2:手动刷新。不管现在缓冲区中有多少数据,想让你直接保存到本地,这就叫做刷新操作,在代码中可以通过 flush()
进行完成。
情况3:释放资源/关流的时候,它也会把缓冲区中的数据保存到本地。
但是 flush()
跟 close()
是有区别的。
二、验证结论
下面是基础代码。其中 a.txt
是空白文件。
FileWriter fw = new FileWriter("myio\\a.txt");
fw.write("我的同学各个都很厉害");
fw.write("说话声音很好听");
fw.write("都是人才");
fw.write("超爱这里哟");
fw.close();
打个断点右键调试一下
![image-20240503174130928](https://img-blog.csdnimg.cn/img_convert/cb63d706a6d111f936da31ee5d266db0.png)
下一步,找到 fw
中,找里面的 bb
双击打开,可以发现,是一个 byte类型
长度为 8192
的字节数组,这个就是缓冲区。
![image-20240503174256875](https://img-blog.csdnimg.cn/img_convert/ab8d0eacb4c41d73ec6c5e59124f81ba.png)
接下来我们不断写出数据的时候,其实就是将这些数据首先按照 UTF-8
进行编码,编码成字节,然后再把这些字节放到缓冲区中。
情况1:缓冲区装满了,它会自动保存到目的地,不需要我们进行任何的操作
FileWriter fw = new FileWriter("myio\\a.txt");
for (int i = 0; i < 8192; i++) {
fw.write(97);
}
//fw.close();
运行完成后,可以发现文件里还是没有数据
![image-20240503174708864](https://img-blog.csdnimg.cn/img_convert/cca03a90c8539288915f5dd73e954022.png)
此时我们可以使用 debug
来运行一下。
但是如果把断点打在这,下面的循环就需要运行很多很多遍,太麻烦了。
![image-20240503174812308](https://img-blog.csdnimg.cn/img_convert/10691709883c6d6ea1eb2ca854d8ff97.png)
此时我们可以在代码下面再去写一条输出语句,然后再将断电打在输出语句的前面,这样我们 debug
后,上面循环里的代码一下就执行完了。
接下来找里面的缓冲区,可以发现里面装满了 97
。
![image-20240503175048399](https://img-blog.csdnimg.cn/img_convert/5a5117d04fbb72befdcca883e86c6ffa.png)
但如果现在将循环的次数改成 8193
,在第 8193次
的时候,缓冲区放不下了,此时缓冲区里面的数据就会自动保存到文件中。
for (int i = 0; i < 8193; i++) {
fw.write(97);
}
可以发现文件里面已经有数据的。
我们可以来看一下文件中有多少个数据,可以发现,就是 8192个字节
。
情况2:手动刷新
不管现在缓冲区中有多少数据,想让你直接保存到本地,这就叫做刷新操作,在代码中可以通过 flush()
进行完成。
FileWriter fw = new FileWriter("myio\\a.txt");
fw.write("我的同学各个都很厉害");
fw.write("说话声音很好听");
fw.flush();
fw.write("都是人才");
fw.write("超爱这里哟");
fw.write("B站");
// fw.close();
执行完成后,可以看见上面的数据已经刷新到本地了,但下面的数据还在缓冲区。
![image-20240503175716746](https://img-blog.csdnimg.cn/img_convert/f554e55757f7fe18ee5e0334fde0c5d1.png)
情况3:释放资源/关流的时候,它也会把缓冲区中的数据保存到本地
在 fw.close()
断流前,它首先会去检查一下缓冲区中有没有数据,如果有,它会把所有剩余的数据都刷新到本地。
FileWriter fw = new FileWriter("myio\\a.txt");
fw.write("我的同学各个都很厉害");
fw.write("说话声音很好听");
fw.flush();
fw.write("都是人才");
fw.write("超爱这里哟");
fw.write("B站");
fw.close();
程序执行完毕,可以发现数据都加载到了本地。
由此也可以看见,如果调了 flush()
,后面还可以继续写数据;
但是如果调用了 close()
,在它的下面就不能继续写数据了,因为 close()
调用完毕后,连接就断开了,如果强行书写,代码就会报错:Stream closed
,它表示流已经断开了,不能再写出数据了。
![image-20240503180046910](https://img-blog.csdnimg.cn/img_convert/b6fb64c3a776aaa9f75172e2277a8a45.png)