IO流:字符输入流Reader的超详细用法及底层原理

简介: IO流:字符输入流Reader的超详细用法及底层原理

一、背景

当我们使用字节输入流时,经常会出现乱码问题,具体原因如下:

  • 解码和编码时的方式不统一
  • 读取数据时未读完整个汉字,因为字节输入流,是一次读一个字节,而一个汉字会占多个字节,当读到某个汉字时,未读完其所有字节,就会出现乱码

二、字符输入流Reader正式出场

核心奥义:

  • 字符输入流Reader,也是一次读一个字节,但是当遇到中文时,就会一次读多个字节,相当于直接读一个汉字出来,这样就解决了字节输入流未读完整个汉字,出现乱码的问题。

字符流 - 底层揭秘

  • 字符流 = 字节流 + 字符集

    字符流特点
  • 字符输入流:一次读一个字节,遇到中文时,一次读多个字节(可能是2个字节或3个字节,这个跟字符集有个哦)【对字符集有疑问的同学可以参考我之前的文章https://flypeppa.blog.csdn.net/article/details/133838023
  • 字符输出流:底层会把数据按照指定的编码方式进行编码,变成字节再写到文件中
  • 最大的特点是,如果文件中有中文,使用字符流操作,不会出现乱码问题

使用场景

  • 对于纯文本文件进行读写操作

三、IO流体系图概览

因为我们本次学习的是字符流,所以看一下字符流的体系图

四、Reader继承人:FileReader出场

1、FileReader读取数据的方法

  • public int read() 读取数据,读到末尾返回-1
  • public int read(char cbuf[]) 读取多个数据,读到末尾返回-1

细节1:按字节进行读取,遇到中文,一次读多个字节,读取后解码,返回一个整数
细节2:读到文件末尾了,read方法返回-1。

2、代码实战

读取单个中文

package com.hidata.devops.paas.demo;
import java.io.FileReader;
import java.io.IOException;
/**
 * @Description :
 * @Date: 2023-10-18 10:59
 */
public class TestsDemo {
    public static void main(String[] args) throws IOException {
        FileReader fir = new FileReader("D:\\devops\\paas\\demo\\d.txt");
        int ch;
        while ((ch = fir.read()) != -1){
            System.out.print((char) ch);
        }
        fir.close();
    }
}

读取多个数据

package com.hidata.devops.paas.demo;
import java.io.FileReader;
import java.io.IOException;
/**
 * @Description :
 * @Date: 2023-10-18 10:59
 */
public class TestsDemo {
    public static void main(String[] args) throws IOException {
        FileReader fir = new FileReader("D:\\devops\\paas\\demo\\d.txt");
        int ch;
        char[] chars = new char[2];
        while ((ch = fir.read(chars)) != -1){
            System.out.println(new String(chars,0,ch));
        }
        fir.close();
    }
}

五、字符流原理解析

1、创建字符输入流对象

底层

  • 关联文件,并创建缓冲区(长度为8192的字节数组)

2、读取数据

底层

  • 1.判断缓冲区中是否有数据可以读取
  • 2.缓冲区没有数据:就从文件中获取数据,装到缓冲区中,每次尽可能装满缓冲区;
    如果文件中也没有数据了,返回-1
  • 3.缓冲区有数据:就从缓冲区中读取。
    空参的read方法:一次读取一个字节,遇到中文一次读多个字节,把字节解码并转成十进制返回;
    有参的read方法:把读取字节,解码,强转三步合并了,强转之后的字符放到数组中

3、代码验证原理

debug代码,看截图

我们发现,一开始就创建了一个缓冲区,长度为8192的字节数组。并且目前缓冲区里面是没有数据的

接下来,我们先往下走一步,

我们发现,第一次读取的时候,他就会把文件里面的所有字节信息都装到缓冲区里面,并且尽可能装满缓冲区。后面再次读取数据的时候,会直接先从缓冲区里面拿,提供效率

4、扩展

文件大小超过缓冲区默认大小(8192)怎么办 ?

  • 如果当前文件的字节数超过缓冲区的大小(8192字节),那么会先把文件的一部分,装满到缓冲区,当缓冲区数据读完之后,再将文件里面剩余的数据,继续装到缓冲区,以此类推。


相关文章
|
2月前
|
设计模式 缓存 Java
【Java技术专题】「入门到精通系列教程」深入探索Java特性中并发编程体系的原理和实战开发指南( 实现可伸缩IO专题)— 上
【Java技术专题】「入门到精通系列教程」深入探索Java特性中并发编程体系的原理和实战开发指南( 实现可伸缩IO专题)— 上
56 0
|
19天前
|
存储 缓存 NoSQL
Redis为什么速度快:数据结构、存储及IO网络原理总结
Redis为什么速度快:数据结构、存储及IO网络原理总结
|
19天前
|
Java 数据处理 开发者
Java IO流专家级教程:深入理解InputStream/OutputStream和Reader/Writer的内部机制
【6月更文挑战第26天】Java IO流涉及字节流(InputStream/OutputStream)和字符流(Reader/Writer),用于高效处理数据输入输出。InputStream/OutputStream处理二进制数据,常使用缓冲提升性能;Reader/Writer处理文本,关注字符编码转换。两者都有阻塞IO操作,但Java NIO支持非阻塞。示例代码展示了如何使用FileInputStream/FileOutputStream和FileReader/FileWriter读写文件。理解这些流的内部机制有助于优化代码性能。
|
19天前
|
Java 开发者
Java IO流实战技巧:如何优化InputStream/OutputStream和Reader/Writer的使用?
【6月更文挑战第26天】Java IO流优化涉及缓冲、资源管理、字符编码和流式处理。使用Buffered流提高读写效率,如`BufferedInputStream`和`BufferedReader`。确保资源关闭使用try-with-resources,如`try (InputStream is = ...) {...}`。处理文本时指定编码,如`InputStreamReader(is, StandardCharsets.UTF_8)`防止乱码。流式处理大文件,分块读写避免内存溢出,以减少内存占用。这些技巧能提升程序性能和健壮性。
|
19天前
|
自然语言处理 Java
Java IO流进阶教程:掌握字节流和字符流的高级用法!
【6月更文挑战第26天】Java IO流助你高效交换数据,包括字节流(InputStream/OutputStream)和字符流(Reader/Writer)的高级技巧。缓冲流(Buffered*)提升读写性能,对象流(Object*Stream)支持对象序列化。字符流的BufferedReader/BufferedWriter优化文本处理,注意字符集如UTF-8用于编码转换。掌握这些,优化IO操作,提升代码质量。
|
19天前
|
Java
Java IO流终极指南:从InputStream/OutputStream到Reader/Writer的全面解读
【6月更文挑战第26天】Java IO流涵盖字节流(InputStream/OutputStream)和字符流(Reader/Writer),前者处理二进制数据,后者专司文本。例如,FileInputStream/FileOutputStream用于文件的字节级读写,而FileReader/FileWriter处理字符级文本。Buffered流提供缓冲功能,提升效率。选择合适的流类取决于数据类型和性能需求。
|
19天前
|
存储 设计模式 Java
Java IO流大揭秘:如何高效使用InputStream/OutputStream和Reader/Writer?
【6月更文挑战第26天】Java IO流核心基础,涉及InputStream/OutputStream(字节流)和Reader/Writer(字符流)。高效使用的关键包括:使用Buffered流提升性能,如BufferedInputStream和BufferedOutputStream;处理编码,通过InputStreamReader和OutputStreamWriter指定如UTF-8编码;应用装饰器模式,如DataOutputStream增强功能。理解并巧妙运用这些技巧能优化数据读写操作。
|
19天前
|
Java
深入探索Java IO流:InputStream/OutputStream与Reader/Writer的奥秘!
【6月更文挑战第26天】Java IO流用于输入输出操作,包括字节流(InputStream/OutputStream)和字符流(Reader/Writer)。InputStream和OutputStream处理字节数据,是所有字节流的基类,可被继承以自定义读写行为。
|
2月前
|
存储 Java
java IO接口(Input)用法
【5月更文挑战第1天】Java的`java.io`包包含多种输入输出类。此示例展示了如何使用`FileInputStream`从`input.txt`读取数据。首先创建`FileInputStream`对象,接着创建一个字节数组存储读取的数据,调用`read()`方法将文件内容填充至数组。然后将字节数组转换为字符串并打印,最后关闭输入流。注意,`InputStream`是抽象类,此处使用其子类`FileInputStream`。其他子类如`ByteArrayInputStream`、`ObjectInputStream`和`BufferedInputStream`各有特定用途。
31 2
|
2月前
|
缓存 Java 数据库
深入理解 Java IO 流:原理与应用
【4月更文挑战第4天】Java IO 浴是处理文件和数据输入输出的关键,涉及数据传输和处理。核心概念包括输入流(从源头读取)和输出流(写入目标),由InputStream和OutputStream接口定义基础操作。具体实现如FileInputStream和FileOutputStream用于文件操作,BufferedInputStream和BufferedOutputStream提升性能。IO流广泛应用于文件操作、网络通信、数据库交互和系统交互。其优点在于灵活性、可扩展性和高效性。使用时注意关闭流、处理异常及选择合适流实现。理解IO流原理和应用能提升编程效率和程序性能。