java nio中字符串编解码核心是charset.encode()/decode()在string与bytebuffer间转换,需注意缓冲区状态、显式指定utf_8等字符集、处理多字节字符边界及避免传统string构造陷阱。

Java NIO 中使用 Charset 编解码字符串,核心是通过 CharsetEncoder 和 CharsetDecoder(或更常用的快捷方法 Charset.encode()/Charset.decode())在 String 与 ByteBuffer 之间转换,适配通道(Channel)读写需求。
用 Charset.encode() 将字符串转为 ByteBuffer(编码)
这是向文件或网络通道写入前的常见步骤。需注意:返回的 ByteBuffer 是只读的、已翻转(position=0, limit=有效字节数),可直接用于 Channel.write()。
- 指定字符集,如
StandardCharsets.UTF_8(推荐,避免字符串硬编码) - 调用
charset.encode(string),内部自动处理编码过程和异常(如MalformedInputException可被抛出) - 若需复用缓冲区或控制容量,可用
CharsetEncoder手动编码,并设置onMalformedInput()和onUnmappableCharacter()策略
示例:
String text = "你好,NIO!"; ByteBuffer buffer = StandardCharsets.UTF_8.encode(text); // buffer 可直接传给 FileChannel.write(buffer) 或 SocketChannel.write(buffer)
用 Charset.decode() 将 ByteBuffer 解码为字符串(解码)
从通道读取字节后,需将 ByteBuffer 中的有效字节区域解码为字符串。关键点是确保 buffer 的 position 和 limit 正确标记待解码范围(通常读完后调用 flip())。
- 解码前务必调用
buffer.flip(),否则可能读到 0 字节或越界 -
charset.decode(buffer)返回新String,原 buffer 不变 - 若 buffer 中含不完整多字节字符(如 UTF-8 中断在中间),默认会抛
MalformedInputException;可通过CharsetDecoder设置codingErrorAction来忽略或替换
示例:
ByteBuffer buffer = ByteBuffer.allocate(1024);
int bytesRead = channel.read(buffer); // 读取数据
if (bytesRead > 0) {
buffer.flip();
String str = StandardCharsets.UTF_8.decode(buffer).toString();
System.out.println(str);
}
处理部分读写与字符边界问题
NIO 是非阻塞/批量操作,一次读可能只拿到半个汉字(UTF-8 下占 3 字节),导致解码失败。不能简单依赖单次 decode()。
- 用
CharsetDecoder配合CodingErrorAction.REPLACE或.IGNORE容错,但会丢失/替换数据 - 更稳妥做法:将未解码完的字节暂存(如用
ByteArrayOutputStream或循环 buffer),等下次读到完整字符再解码 - 对文本协议(如 HTTP、自定义行协议),建议按行或按帧解析,而非盲目 decode 整个 buffer
避免常见陷阱
- 别用
new String(byte[], charset)+String.getBytes(charset)—— 这是传统 IO 方式,在 NIO 场景下绕过ByteBuffer失去零拷贝优势 - 不要重复调用
encode()对同一字符串——每次新建 buffer,无缓存;高频场景可复用CharsetEncoder - 注意平台默认编码(
Charset.defaultCharset())不可靠,尤其跨平台部署时,必须显式指定(如UTF_8) -
ByteBuffer.array()获取底层字节数组时,要结合arrayOffset()和limit(),否则可能包含无效前置/尾部数据
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











