【Java】`字符输出流` 的底层原理超详解

一、画图分析

其实也不难,就是多了一个缓冲区而已。

在输出的时候首先要有一个目的地,假设编码规则还是 UTF-8,现在我要利用字符输出流,将数据写到文件中。

当我们创建字符输出流(FileWriter)对象的时候,那就好比内存跟文件之间有了这么一个连接通道。

与此同时在创建 FileWriter对象 的时候,也创建了一个长度为 8192的字节数组,其实就是我们刚刚所说的缓冲区。

image-20240503172801860

接下来会用下面的代码去写出数据。

在写出的时候它会把所有的数据按照 UTF-8 进行编码,一个中文变成三个字节,一个英文变成一个字节。

在写的时候跟字节流是不一样的,字节流没有缓冲区,它是直接写到文件的目的地的。

但是字符流是有缓冲区的,它是先写到缓冲区中。

image-20240503173034985

那数据什么时候才能真正的保存到目的地呢?有三种情况。

情况1:缓冲区装满了,它会自动保存到目的地,不需要我们进行任何的操作。

情况2:手动刷新。不管现在缓冲区中有多少数据,想让你直接保存到本地,这就叫做刷新操作,在代码中可以通过 flush() 进行完成。

情况3:释放资源/关流的时候,它也会把缓冲区中的数据保存到本地。

但是 flush()close() 是有区别的。

image-20240503173901033


二、验证结论

下面是基础代码。其中 a.txt 是空白文件。

FileWriter fw = new FileWriter("myio\\a.txt");

fw.write("我的同学各个都很厉害");
fw.write("说话声音很好听");
fw.write("都是人才");
fw.write("超爱这里哟");

fw.close();

打个断点右键调试一下

image-20240503174130928

下一步,找到 fw 中,找里面的 bb 双击打开,可以发现,是一个 byte类型 长度为 8192 的字节数组,这个就是缓冲区。

image-20240503174256875

接下来我们不断写出数据的时候,其实就是将这些数据首先按照 UTF-8 进行编码,编码成字节,然后再把这些字节放到缓冲区中。


情况1:缓冲区装满了,它会自动保存到目的地,不需要我们进行任何的操作

FileWriter fw = new FileWriter("myio\\a.txt");

for (int i = 0; i < 8192; i++) {
    fw.write(97);
}

//fw.close();

运行完成后,可以发现文件里还是没有数据

image-20240503174708864

此时我们可以使用 debug 来运行一下。

但是如果把断点打在这,下面的循环就需要运行很多很多遍,太麻烦了。

image-20240503174812308

此时我们可以在代码下面再去写一条输出语句,然后再将断电打在输出语句的前面,这样我们 debug 后,上面循环里的代码一下就执行完了。

接下来找里面的缓冲区,可以发现里面装满了 97

image-20240503175048399

但如果现在将循环的次数改成 8193,在第 8193次 的时候,缓冲区放不下了,此时缓冲区里面的数据就会自动保存到文件中。

for (int i = 0; i < 8193; i++) {
    fw.write(97);
}

可以发现文件里面已经有数据的。

image-20240503175215222

我们可以来看一下文件中有多少个数据,可以发现,就是 8192个字节

image-20240503175433790


情况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

情况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();

程序执行完毕,可以发现数据都加载到了本地。

image-20240503175849985

由此也可以看见,如果调了 flush(),后面还可以继续写数据;

但是如果调用了 close(),在它的下面就不能继续写数据了,因为 close() 调用完毕后,连接就断开了,如果强行书写,代码就会报错:Stream closed,它表示流已经断开了,不能再写出数据了。

image-20240503180046910
  • 23
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值