字节流转字符串必须显式指定与原始数据一致的字符编码,推荐用InputStreamReader+BufferedReader组合(如new InputStreamReader(is, StandardCharsets.UTF_8)),配合try-with-resources和逐行读取,避免默认编码导致乱码。

关键就一条:字节流转字符串时,必须显式指定与原始数据一致的字符编码,不能依赖平台默认编码。
明确知道编码类型时,用 InputStreamReader + BufferedReader
这是最稳妥、最常用的方式,尤其适合读取文件、网络响应等真实流场景。
- 直接传入编码名(如 StandardCharsets.UTF_8),避免字符串拼写错误
- 用 try-with-resources 自动关闭流,防止资源泄漏
- 逐行读取比一次性读完更省内存,也便于处理大文本
示例代码:
try (InputStream is = new FileInputStream("data.txt");
InputStreamReader isr = new InputStreamReader(is, StandardCharsets.UTF_8);
BufferedReader reader = new BufferedReader(isr)) {
String content = reader.lines().collect(Collectors.joining("\n"));
System.out.println(content);
}
分析 Java Spring Boot 后端 Controller 代码,自动生成 Markdown 格式的接口文档。当用户说“生成 Java 接口文档”、“生成 API 文档”、“从 Spring 代码生成文档”时触发。
立即学习“Java免费学习笔记(深入)”;
字节数组已存在时,用 new String(byte[], charset) 构造器
适用于从 socket、数据库 Blob、Base64 解码后等拿到 byte[] 的情况。
- 绝对不要用 new String(byte[]) 无参构造——它调用系统默认编码,Windows 常是 GBK,Linux/macOS 常是 UTF-8,极易出错
- 中文、emoji、特殊符号务必用 UTF-8;旧系统对接可能需 GBK 或 ISO-8859-1,但要确认来源
- 若不确定编码,可先尝试 UTF-8,失败再试 GBK,但生产环境应杜绝“猜编码”
注意 BOM 和非法字节的干扰
有些 UTF-8 文件开头带 BOM(EF BB BF),直接 new String 会把这三个字节当内容显示为乱码字符。
- 可用 new String(bytes, offset, length, charset) 跳过前 3 字节(需先校验数组长度)
- 或用第三方库如 Apache Commons IO 的 IOUtils.toString(is, charset),它自动跳过 UTF-8 BOM
- 遇到
MalformedInputException,说明字节序列本身不合法(比如截断的 UTF-8),需检查数据完整性
避免踩坑的硬性建议
- 开发阶段就在 JVM 启动参数加 -Dfile.encoding=UTF-8,统一默认编码(仅辅助,不能替代显式指定)
- HTTP 接口返回头中若有
Content-Type: text/plain; charset=GBK,就必须用 GBK 解码,不能硬套 UTF-8 - Base64 字符串不是“编码后的字节”,而是文本编码。别对 Base64 字符串调用 getBytes() 再 new String()——那是双重乱码
- 日志里打印 byte[] 时,用 Arrays.toString() 或十六进制输出,方便比对原始字节是否符合预期编码

















