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. InputStreamReader
        • 3. OutputStreamWriter
        • 4. 为什么一定要指定字符集
        • 5. 常见应用场景
          • 5.1 读取 HTTP 请求体
          • 5.2 处理指定编码文件
          • 5.3 网络协议文本解析
        • 6. 与 Files API 的关系
        • 专家实践清单
        • Tips 快问快答
        • 7. 总结
      • 装饰器模式与IO设计
    • 常用IO流

    • 文件与目录操作

    • Java NIO

    • 高级主题

    • 实践与性能优化

    • 面试与设计题

    • IO实践速查

  • JVM

目录

字节流与字符流的转换

字节流和字符流之间的转换是 Java IO 中非常重要的一块。它解决的问题是:底层数据以字节形式存在,但业务代码希望按字符处理文本。

# 1. 转换流是什么

Java 提供了两个转换流:

  • InputStreamReader:把字节输入流转换为字符输入流。
  • OutputStreamWriter:把字符输出流转换为字节输出流。
InputStream  -> InputStreamReader  -> Reader
OutputStream <- OutputStreamWriter <- Writer

转换时必须关注字符集。

# 2. InputStreamReader

InputStreamReader 用于把字节解码成字符。

import java.io.BufferedReader;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.nio.charset.StandardCharsets;

public class InputStreamReaderDemo {
    public static void main(String[] args) throws IOException {
        try (BufferedReader reader = new BufferedReader(
                new InputStreamReader(new FileInputStream("demo.txt"), StandardCharsets.UTF_8))) {

            String line;
            while ((line = reader.readLine()) != null) {
                System.out.println(line);
            }
        }
    }
}

这里的数据处理过程是:

文件字节 -> FileInputStream -> InputStreamReader按UTF-8解码 -> BufferedReader按行读取

# 3. OutputStreamWriter

OutputStreamWriter 用于把字符编码成字节。

import java.io.BufferedWriter;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.nio.charset.StandardCharsets;

public class OutputStreamWriterDemo {
    public static void main(String[] args) throws IOException {
        try (BufferedWriter writer = new BufferedWriter(
                new OutputStreamWriter(new FileOutputStream("demo.txt"), StandardCharsets.UTF_8))) {

            writer.write("Java IO 转换流");
            writer.newLine();
        }
    }
}

数据处理过程是:

Java字符 -> OutputStreamWriter按UTF-8编码 -> FileOutputStream -> 文件字节

# 4. 为什么一定要指定字符集

乱码的根本原因通常是编码和解码使用的字符集不一致。

写入时:字符 -> UTF-8字节
读取时:GBK字节 -> 字符

如果写入和读取的字符集不一致,程序仍然能读到数据,但读出来的字符可能是错误的。

推荐写法:

new InputStreamReader(inputStream, StandardCharsets.UTF_8);
new OutputStreamWriter(outputStream, StandardCharsets.UTF_8);

不推荐依赖默认字符集:

new InputStreamReader(inputStream);
new OutputStreamWriter(outputStream);

# 5. 常见应用场景

# 5.1 读取 HTTP 请求体

Web 容器底层接收到的是字节,但业务代码需要文本 JSON:

try (BufferedReader reader = new BufferedReader(
        new InputStreamReader(request.getInputStream(), StandardCharsets.UTF_8))) {
    String body = reader.lines().collect(java.util.stream.Collectors.joining("\n"));
}

# 5.2 处理指定编码文件

老系统经常有 GBK 文件:

try (BufferedReader reader = new BufferedReader(
        new InputStreamReader(new FileInputStream("legacy.txt"), Charset.forName("GBK")))) {
    // process text
}

# 5.3 网络协议文本解析

Socket 中传输的是字节,如果协议内容是文本,就需要转换流。

# 6. 与 Files API 的关系

现代 Java 代码中,更推荐直接使用 NIO.2 提供的封装:

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

这些方法内部已经完成了字节流、字符集、缓冲能力的组合,代码更简洁。

# 专家实践清单

场景 组合方式 注意点
字节输入转文本 InputStreamReader 指定源数据编码
文本输出转字节 OutputStreamWriter 指定目标文件编码
网络协议文本部分 字节流 + 显式解码 先识别消息边界
文件编码转换 Reader + Writer 不要用默认编码中转

转换流的定位:

InputStream
  │ byte
  ▼
InputStreamReader
  │ char
  ▼
Reader / BufferedReader

Writer / BufferedWriter
  │ char
  ▼
OutputStreamWriter
  │ byte
  ▼
OutputStream

# Tips 快问快答

Q:转换流解决什么问题? A:解决字节流和字符流之间的编码/解码转换问题。

Q:InputStreamReader 做什么? A:把字节输入流按指定字符集解码成字符输入流。

Q:OutputStreamWriter 做什么? A:把字符输出按指定字符集编码成字节输出。

Q:为什么构造转换流时必须传 Charset? A:避免使用平台默认编码导致跨环境乱码。

Q:转换流能不能修复已经乱码的文本? A:通常不能,只能在源字节还没有被错误解码前正确处理。

Q:网络文本协议一定要用字符流吗? A:不一定。很多协议要先按字节识别边界,再对文本字段解码。

Q:Files.newBufferedReader 和转换流是什么关系? A:它内部已经封装了字节到字符的转换和缓冲能力。

Q:最常见的转换流错误是什么? A:读写两端使用不同编码,或者中间多次错误转码。

# 7. 总结

转换流是字节流和字符流之间的桥梁。只要底层数据是字节,而业务语义是文本,就需要考虑转换流。生产代码中最重要的实践是显式指定字符集,并保证写入和读取使用一致的编码规则。

上次更新: 2026/06/25, 14:19:18
字符流
装饰器模式与IO设计

← 字符流 装饰器模式与IO设计→

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