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流

    • 文件与目录操作

    • Java NIO

    • 高级主题

      • RandomAccessFile
      • 内存映射文件MappedByteBuffer
      • 零拷贝
      • BIO-NIO-AIO模型
      • 字符集与乱码
        • 1. 字符、编码、字符集
        • 2. 编码和解码
        • 3. Java 中指定字符集
        • 4. 不推荐依赖默认字符集
        • 5. 常见乱码场景
          • 5.1 文件乱码
          • 5.2 HTTP 请求乱码
          • 5.3 数据库乱码
          • 5.4 日志乱码
        • 6. UTF-8 为什么常用
        • 7. 乱码排查步骤
        • 专家实践清单
        • Tips 快问快答
        • 8. 总结
      • 序列化安全与替代方案
    • 实践与性能优化

    • 面试与设计题

    • IO实践速查

  • JVM

目录

字符集与乱码

乱码是 Java IO 中最常见的问题之一。它不是玄学,本质上是编码和解码规则不一致。

# 1. 字符、编码、字符集

字符是人能理解的文字或符号,例如 A、中、。。

计算机只能存储字节,所以字符需要编码成字节。

字符集定义了字符和字节之间的映射规则。

常见字符集:

  • UTF-8
  • UTF-16
  • GBK
  • ISO-8859-1

# 2. 编码和解码

写入文本时:

字符 -> 按字符集编码 -> 字节

读取文本时:

字节 -> 按字符集解码 -> 字符

乱码出现的典型原因:

写入时使用 UTF-8
读取时使用 GBK

规则不一致,结果就可能错误。

# 3. Java 中指定字符集

推荐统一使用 StandardCharsets。

byte[] bytes = "中文".getBytes(StandardCharsets.UTF_8);
String text = new String(bytes, StandardCharsets.UTF_8);

读文件:

Files.newBufferedReader(path, StandardCharsets.UTF_8);

写文件:

Files.newBufferedWriter(path, StandardCharsets.UTF_8);

# 4. 不推荐依赖默认字符集

不推荐:

new String(bytes);
"中文".getBytes();
new FileReader("a.txt");
new FileWriter("a.txt");

这些写法依赖默认字符集。虽然 Java 18 起默认字符集统一为 UTF-8,但为了跨版本、跨运行环境和代码可读性,生产代码仍建议显式指定字符集。

# 5. 常见乱码场景

# 5.1 文件乱码

文件实际是 GBK,代码按 UTF-8 读:

Files.readString(path, StandardCharsets.UTF_8);

解决:确认文件真实编码,并使用一致字符集。

# 5.2 HTTP 请求乱码

请求体编码、服务端解析编码、响应编码不一致。

解决:

  • 请求和响应统一 UTF-8。
  • Content-Type 明确声明 charset=UTF-8。
  • 服务端读取流时显式指定编码。

# 5.3 数据库乱码

应用、JDBC、数据库、表字段字符集不一致。

解决:统一连接参数、数据库字符集、表字符集和应用编码。

# 5.4 日志乱码

日志框架编码、控制台编码、文件查看工具编码不一致。

解决:统一日志输出编码和查看工具编码。

# 6. UTF-8 为什么常用

UTF-8 的优点:

  • 兼容 ASCII。
  • 支持全世界大部分字符。
  • 英文内容空间占用小。
  • Web、Linux、数据库、现代工具链广泛使用。

现代系统中,除非有老系统兼容要求,建议统一使用 UTF-8。

# 7. 乱码排查步骤

  1. 确认原始数据是什么编码。
  2. 确认读取时使用什么编码。
  3. 确认中间传输有没有再次转码。
  4. 确认输出端或查看工具使用什么编码。
  5. 避免反复 new String(str.getBytes(...), ...) 盲目试错。

# 专家实践清单

检查点 要确认什么 常见问题
数据源 原始字节使用什么编码 文件实际不是 UTF-8
读取端 程序用什么 Charset 解码 使用默认编码
传输层 HTTP/消息是否声明编码 Header 与内容不一致
存储层 数据库字段和连接编码 写入正常读取乱码
输出端 终端、浏览器、日志查看器编码 查看工具解码错误

乱码排查链路:

原始字节
  │ 正确编码?
  ▼
程序解码
  │ 正确 Charset?
  ▼
内部 String
  │ 是否重复转码?
  ▼
输出编码
  │ 查看工具是否一致?

# Tips 快问快答

Q:乱码的本质是什么? A:同一组字节被使用错误的字符集解码,或编码解码链路不一致。

Q:Java String 内部是乱码的吗? A:String 是字符序列,乱码通常发生在字节和字符转换边界。

Q:为什么默认编码危险? A:不同操作系统、容器镜像、JDK 配置可能默认编码不同。

Q:UTF-8 能表示中文吗? A:能,UTF-8 是 Unicode 的变长编码形式。

Q:ISO-8859-1 读取中文会怎样? A:会把中文 UTF-8 字节按单字节字符解释,通常出现乱码。

Q:如何确认文件真实编码? A:查看来源系统、协议声明、编辑器编码和原始字节特征,不要只猜。

Q:为什么反复 getBytes/new String 不可靠? A:如果已经错误解码,原始字节信息可能丢失。

Q:生产代码最稳的原则是什么? A:入口、存储、传输、输出都显式声明并统一 UTF-8。

# 8. 总结

乱码的根因几乎总是编码和解码不一致。资深工程师处理乱码问题不会靠猜,而是沿着“数据源编码 -> 传输编码 -> 程序解码 -> 输出编码”逐段确认。生产代码中最重要的原则是显式指定字符集,并尽量统一 UTF-8。

上次更新: 2026/06/25, 14:19:18
BIO-NIO-AIO模型
序列化安全与替代方案

← BIO-NIO-AIO模型 序列化安全与替代方案→

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