inputstreamreader 不直接区分 utf-16be 和 utf-16le,需显式指定编码名(如 "utf-16be" 或 "utf-16le");用 "utf-16" 可自动识别 bom,但无 bom 时行为不跨版本一致,手动翻转字节错误且危险,应确保编码参数与实际字节序匹配。

InputStreamReader 本身不直接区分 UTF-16BE 和 UTF-16LE,而是依赖底层 InputStream 提供的字节流和指定的字符集名称来决定如何解码。关键在于:你必须显式指定编码名(如 "UTF-16BE" 或 "UTF-16LE"),否则默认使用平台默认编码或 BOM 自动检测逻辑(仅对 "UTF-16" 有效)。
明确指定编码名称是最可靠的方式
如果你已知输入数据是纯 UTF-16BE 或 UTF-16LE(不含 BOM),就不要用 "UTF-16",而应直接写死编码名:
- UTF-16 大端(Big-Endian)→ 使用
"UTF-16BE" - UTF-16 小端(Little-Endian)→ 使用
"UTF-16LE" - 避免用
"UTF-16",除非你确定输入含 BOM 或接受默认行为(JDK 会按 BOM 判断;无 BOM 时多数 JDK 版本默认按 BE 解析,但不保证跨版本一致)
让 InputStreamReader 自动识别 BOM(仅限 "UTF-16")
如果输入流开头可能有 BOM(FE FF 表示 BE,FF FE 表示 LE),可传入 "UTF-16":
- JDK 的
InputStreamReader在使用"UTF-16"时会读取前 2 字节检查 BOM - 匹配到
FE FF→ 按 UTF-16BE 解码 - 匹配到
FF FE→ 按 UTF-16LE 解码 - 无 BOM 时行为因 JDK 版本而异(OpenJDK 通常回退为 UTF-16BE),不建议依赖
注意 InputStream 的字节顺序不能靠“转换”来修复
UTF-16BE/LE 是字节序差异,不是内容错误。你不能也不该用 Java 字节操作去“翻转”字节再喂给 InputStreamReader:
- 手动交换每两个字节极易出错(比如遇到 surrogate pair 或单字节 ASCII 会破坏数据)
- 正确做法是让
InputStreamReader按真实编码解析——它内部已处理好字节序与 Unicode 码点映射 - 若原始流字节序与指定编码不符(例如用 UTF-16LE 解析实际是 BE 的流),结果必然乱码,此时应修正编码参数而非字节
实用建议:封装一个安全的 UTF-16 Reader
可写一个工具方法,优先尝试 BOM 检测, fallback 到显式指定:
- 先 peek 前 2 字节判断 BOM,再构造对应
InputStreamReader - 或统一用
"UTF-16"并确保源数据带标准 BOM(推荐用于文件读取) - 网络传输或内存流若无法控制 BOM,务必约定好端到端的字节序,并硬编码
"UTF-16BE"/"UTF-16LE"
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











