Wrayの知识库 Wrayの知识库
首页
  • Java 基础
  • Java 集合
  • Java 并发
  • Java IO
  • JVM
  • Spring Framework
  • Spring Boot
  • Spring Cloud
  • Spring Security
  • MySQL
  • Redis
  • 计算机基础
  • 操作系统原理
  • Linux
  • MacOS
  • Windows
  • 系统工程与研究专题
  • AI 基础
  • 大模型基础
  • Prompt 工程
  • RAG 检索增强生成
  • Agent 智能体
  • AI 应用开发
  • AI 工程化
  • AI 安全与治理
  • AI 面试与设计题
  • 纸质书
  • 电子书
  • 学习课程
疑难杂症
GitHub (opens new window)
首页
  • Java 基础
  • Java 集合
  • Java 并发
  • Java IO
  • JVM
  • Spring Framework
  • Spring Boot
  • Spring Cloud
  • Spring Security
  • MySQL
  • Redis
  • 计算机基础
  • 操作系统原理
  • Linux
  • MacOS
  • Windows
  • 系统工程与研究专题
  • AI 基础
  • 大模型基础
  • Prompt 工程
  • RAG 检索增强生成
  • Agent 智能体
  • AI 应用开发
  • AI 工程化
  • AI 安全与治理
  • AI 面试与设计题
  • 纸质书
  • 电子书
  • 学习课程
疑难杂症
GitHub (opens new window)
  • Java章节编写规范
  • Java基础

  • Java集合

  • Java并发

  • Java IO

    • Java IO概述
    • IO基础

      • IO流体系
      • 字节流
      • 字符流
        • 1. 为什么需要字符流
        • 2. 字符流的核心类
        • 3. 读取文本文件
        • 4. 写入文本文件
        • 5. FileReader 和 FileWriter 的注意点
        • 6. 字符流适合什么场景
        • 7. 字符流与编码的关系
        • 专家实践清单
        • Tips 快问快答
        • 8. 总结
      • 字节流与字符流的转换
      • 装饰器模式与IO设计
    • 常用IO流

    • 文件与目录操作

    • Java NIO

    • 高级主题

    • 实践与性能优化

    • 面试与设计题

    • IO实践速查

  • JVM

目录

字符流

字符流用于处理文本数据。和字节流不同,字符流关心的是字符,而不是原始字节。只要涉及中文、英文、符号、换行、配置文件、日志、JSON、XML 等文本内容,就应该优先考虑字符流。

# 1. 为什么需要字符流

计算机底层存储的是字节,但人阅读的是字符。字符和字节之间需要通过字符集转换。

例如字符串 "中国":

  • 使用 UTF-8 编码通常占 6 个字节。
  • 使用 GBK 编码通常占 4 个字节。

如果直接用字节流逐字节处理文本,很容易在多字节字符中间截断,导致乱码。字符流会帮我们完成字节到字符的解码,或者字符到字节的编码。

# 2. 字符流的核心类

字符流的两个顶层抽象类是:

  • Reader:字符输入流。
  • Writer:字符输出流。

常用方法如下:

int read()
int read(char[] cbuf)
int read(char[] cbuf, int off, int len)

void write(int c)
void write(char[] cbuf)
void write(String str)
void flush()
void close()

# 3. 读取文本文件

推荐使用 Files.newBufferedReader 并显式指定字符集。

import java.io.BufferedReader;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;

public class ReadTextDemo {
    public static void main(String[] args) throws IOException {
        Path path = Path.of("application.log");

        try (BufferedReader reader = Files.newBufferedReader(path, StandardCharsets.UTF_8)) {
            String line;
            while ((line = reader.readLine()) != null) {
                System.out.println(line);
            }
        }
    }
}

readLine() 不会把行尾换行符返回。如果写出时需要保留换行,需要自己追加。

# 4. 写入文本文件

import java.io.BufferedWriter;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;

public class WriteTextDemo {
    public static void main(String[] args) throws IOException {
        Path path = Path.of("result.txt");

        try (BufferedWriter writer = Files.newBufferedWriter(path, StandardCharsets.UTF_8)) {
            writer.write("第一行");
            writer.newLine();
            writer.write("第二行");
        }
    }
}

newLine() 会写入当前系统的换行符。如果需要跨平台固定输出格式,可以直接写 \n。

# 5. FileReader 和 FileWriter 的注意点

FileReader 和 FileWriter 使用起来简单:

try (Reader reader = new FileReader("a.txt")) {
    // read text
}

但它们的主要问题是字符集不够直观。旧版本 Java 中默认字符集依赖操作系统环境,容易出现“本地正常、服务器乱码”的问题。Java 18 起默认字符集统一为 UTF-8,但生产代码仍建议显式指定字符集,让代码意图更清晰。

推荐:

Files.newBufferedReader(path, StandardCharsets.UTF_8);
Files.newBufferedWriter(path, StandardCharsets.UTF_8);

# 6. 字符流适合什么场景

适合使用字符流的场景:

  • 读取配置文件。
  • 读取 CSV、JSON、XML 等文本文件。
  • 处理日志文件。
  • 生成 SQL、HTML、Markdown 等文本。
  • 需要按行读取的场景。

不适合使用字符流的场景:

  • 图片、视频、音频。
  • 压缩包。
  • 加密后的字节。
  • 任意二进制协议。

# 7. 字符流与编码的关系

字符流不是完全脱离字节流存在的。真正读写文件时,底层仍然是字节:

读取文本:字节 -> 按字符集解码 -> 字符
写入文本:字符 -> 按字符集编码 -> 字节

所以字符流的关键不是“比字节流高级”,而是“封装了字符集转换”。

# 专家实践清单

场景 推荐 API 关键点
读取 UTF-8 文本 Files.newBufferedReader 显式指定 StandardCharsets.UTF_8
写入文本 Files.newBufferedWriter 明确覆盖、追加和创建策略
按行处理日志 BufferedReader.readLine 注意行尾换行符会被去掉
编码转换 InputStreamReader + OutputStreamWriter 源编码和目标编码都要明确

字符流背后的转换链路:

磁盘/网络字节
  │ CharsetDecoder
  ▼
Java char / String
  │ 业务处理
  ▼
Java char / String
  │ CharsetEncoder
  ▼
磁盘/网络字节

# Tips 快问快答

Q:字符流适合什么场景? A:适合处理文本,例如配置、日志、CSV、模板文件。

Q:字符流是否不需要关心编码? A:需要。字符流只是封装了编码/解码过程,仍然必须指定字符集。

Q:为什么不建议直接用 FileReader? A:它使用平台默认字符集,跨环境容易乱码。

Q:BufferedReader.readLine() 会保留换行符吗? A:不会,返回内容不包含行尾换行符。

Q:文本文件能不能用字节流读? A:可以,但需要手动把字节按正确字符集解码为字符。

Q:乱码的本质是什么? A:写入时编码和读取时解码使用的字符集不一致。

Q:生产环境推荐统一什么编码? A:通常统一 UTF-8,并在代码、配置、数据库和传输层显式声明。

Q:字符流最大的边界是什么? A:它不适合处理任意二进制数据,否则可能破坏原始字节。

# 8. 总结

字符流专门用于文本处理。只要处理的是人可读文本,就应该优先使用字符流,并显式指定字符集。生产代码中最常见、最稳妥的组合是 Files.newBufferedReader、Files.newBufferedWriter 和 StandardCharsets.UTF_8。

上次更新: 2026/06/25, 14:19:18
字节流
字节流与字符流的转换

← 字节流 字节流与字符流的转换→

Copyright © 2023-2026 Wray | 鄂ICP备2024050235号-1
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式