当前位置: 首页 > news >正文

【Java IO流】字符流详解

文章目录

  • 1. 前言
  • 2. 字符输入流
  • 3. 字符输出流
  • 4. 字符流底层原理解析
    • 4.1 字符输入流
    • 4.2 字符输出流

1. 前言

在上一篇字符集详解中我们说到了产生乱码的原因,要么是读取数据时未读完整个汉字,要么是因为编码和解码的方式不统一,对于后者我们只需要规定好编码和解码的方式,而要解决读取数据时未读完整个汉字的问题,我们必须要有一个在遇到汉字时一次读取多个字节的方法,字符流应运而生。

其实,字符流的底层依然是字节流的方式,在读取英文等字符时一次读取一个字节,不同的是,当遇到中文时,会一次读取多个字节。我们已经学习了字节流中的文件 FileOutputStream 类和 FileInputStream 类,现在我们可以按照前面的方法继续学习。

image-20230116215921721

首先,在字符流中有两个基本类,分别是字符输入流 Reader 类和字符输出流 Writer 类,这两个类都是抽象类,不能实例化对象,我们一般使用其子类创建对象完成数据的写出和读取。

2. 字符输入流

我们可以使用字符输入流 FileReader 把本地文件中的数据读取到程序中,该类在使用时分为以下三个步骤:

  1. 创建流对象
  2. 读取数据
  3. 释放资源/关流

示例:

import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;

public class Test {
    public static void main(String[] args) throws IOException {
        //创建流对象
        FileReader fileReader = new FileReader("test.txt");
        //读取数据
        int b;
        while((b=fileReader.read())!=-1){
            System.out.print((char)b);
        }
        //释放资源
        fileReader.close();

    }
}

在 read() 方法中,程序会把读取到的数据进行解码并转换成 字符集表中对应的十进制数,其底层还是字节流的方式,只是在遇到中文时一次读取多个字节并解码转为字符集表中对应的十进制数。程序中的异常直接抛出即可。

同样,我们也可以往 read() 方法中传入一个数组,表示一次读取多个字符并存入数组中,与空参的 read() 方法不同的是,带参数的方法返回每次读取的数据个数,这个数字由数组的大小决定。读取到文件末尾时返回 -1。

示例:

import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;

public class Test {
    public static void main(String[] args) throws IOException {
        //创建流对象
        FileReader fileReader = new FileReader("test.txt");
        //读取数据
        char[] chars = new char[2];
        int len;
        while((len=fileReader.read(chars))!=-1){
            System.out.println(new String(chars,0,len));
        }
        //释放资源
        fileReader.close();
    }
}

读取数据是一个解码的过程。

3. 字符输出流

使用字符输出流 FileWriter 往本地文件中写出数据有两种方式:

  • 清空文件,把数据写入文件中
  • 把数据追加到文件末尾

在创建 FileWriter 类对象时,参数既可以是 String 类型也可以是 File 类对象,如果传入String 类型,其底层同样会创建 File 类对象。写入数据时,如果文件不存在,则会创建文件并写入数据,但是要保证父级路径正确,如果文件存在,默认会清空 文件并写入数据,如果想要追加写入,则传入参数 true 。

示例:

import java.io.FileWriter;
import java.io.IOException;

public class Test {
    public static void main(String[] args) throws IOException {
        //创建流对象
        FileWriter fileWriter = new FileWriter("test.txt",true);
        String s="Java你好";
        char[] chars=s.toCharArray();
        //写入数据
        fileWriter.write(97);//写出一个字符
        fileWriter.write(s);//写出一个字符串
        fileWriter.write(s,1,2);//写出一个字符串的一部分

        fileWriter.write(chars);//写出一个字符数组
        fileWriter.write(chars,2,3);//写出一个字符数组的一部分
        //释放资源
        fileWriter.close();
    }
}

写出一个字符时,write() 方法传入的参数是要写入文件的字符在字符集中对应的十进制数,写出数据其实是一个编码的过程。

4. 字符流底层原理解析

接下来我们一起探讨一下字符流的底层原理,

4.1 字符输入流

当我们创建一个文件字符输入流的对象时,其底层会在内存中创建一个缓冲区,该缓冲区是一个大小为 8192 的字节数组,在读取数据时,Java 首先会判断缓冲区中是否有数据,如果缓冲区中没有数据,则会从文件中读取数据,并且尽量充满缓冲区,如果缓冲区中有数据,则会从缓冲区中读取数据,直到读取完该区的数据,Java 会继续从文件中往缓冲区读取数据并且尽量充满缓冲区,直到读取到文件末尾,返回 -1。

使用Debug的方法查看缓冲区:

import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;

public class Test {
    public static void main(String[] args) throws IOException {
        //创建流对象
        FileReader fileReader = new FileReader("test.txt");
        //读取数据
        fileReader.read();
        //释放资源
        fileReader.close();
    }
}

image-20230116234500447

4.2 字符输出流

同样的,在我们创建文件字符输出流的同时,其底层会在内存中创建一个大小为 8192 的缓冲区,该缓冲区是一个字节数组。在写出数据时,首先会把数据按照UTF-8 的编码方式编码,然后写到这个缓冲区中,那么什么时候数据会被写到文件中呢?

image-20230116234043097

以下三种情况缓冲区数据会被写入文件:

  1. 缓冲区装满了
  2. 调用成员方法 flush() 刷新
  3. 关流

我们下期见!

相关文章:

  • 线段树入门
  • 【C语言从0到1之文件操作】(原理 画图 举例 不信教不会你 不要放收藏夹落灰 学起来好嘛)
  • java的数据类型:引用数据类型(String、数组、枚举)
  • linux系统管理
  • 2023牛客寒假算法基础集训营2(11/12)
  • linux搭建webapp实战
  • Golang语法快速上手3
  • 【JavaEE初阶】第五节.多线程 ( 基础篇 ) 线程安全问题(上篇)
  • Java技能树-操作符(二)-练习篇
  • 化繁为简、性能提升 -- 在WPF程序中,使用Freetype库心得
  • 用通知-等待机制优化锁等待问题
  • 微电网(风、光、储能、需求响应)【Simulink 仿真实现】
  • Mysql安全之权限用户管理参考手册
  • C语言萌新如何使用printf函数?
  • 【Kotlin】类的继承 ① ( 使用 open 关键字开启类的继承 | 使用 open 关键字开启方法重写 )
  • [网鼎杯 2020 青龙组]AreUSerialz
  • Windows 服务器刷题(带答案)
  • docker入门(二):docker的常用命令
  • colab 如何释放gpu显存?
  • CANoe-仿真总线上的红蓝线、“CANoe DEMO“ license下的软件限制
  • https://app.hackthebox.com/machines/Inject
  • Spring —— Spring简单的读取和存储对象 Ⅱ
  • 渗透测试之冰蝎实战
  • Mybatis、TKMybatis对比
  • Microsoft Office 2019(2022年10月批量许可版)图文教程
  • 《谷粒商城基础篇》分布式基础环境搭建
  • 哈希表题目:砖墙
  • Vue 3.0 选项 生命周期钩子
  • 【车载嵌入式开发】AutoSar架构入门介绍篇
  • 【计算机视觉 | 目标检测】DETR风格的目标检测框架解读