ByteBuffer::asCharBuffer返回的CharBuffer首字符为何总是空格?
问题解析:CharBuffer输出开头空格与长度异常的原因及解决办法
嘿,这可不是Java NIO类库的Bug,其实是你对UTF-16编码的**字节顺序标记(BOM)**特性不熟悉导致的,我来给你拆解清楚:
核心原因:UTF-16的BOM被当成了普通字符
当你执行"hello".getBytes(Charset.forName("UTF-16"))时,Java的UTF-16编码默认会在字节数组的开头添加字节顺序标记(BOM)——这是两个字节的0xFE 0xFF(对应大端字节序的标识),用来告诉后续解析器字节的排列顺序。
但当你把包含BOM的字节数组直接包装成ByteBuffer再转成CharBuffer时,CharBuffer会把开头的BOM字节解析成一个Unicode字符:\uFEFF(零宽无间断空格)。这个字符在控制台输出时通常会显示为一个空格,同时它也会被算入CharBuffer的长度中,所以你看到buffer.length()返回6(5个"hello"字符+1个BOM字符),输出开头就多了个空格。
解决办法
你可以通过两种方式解决这个问题:
1. 使用不带BOM的UTF-16编码变体
直接指定UTF-16BE(大端序)或UTF-16LE(小端序)编码,这些编码不会自动生成BOM:
public static void main(String[] args) { byte[] byteArray = "hello".getBytes(Charset.forName("UTF-16BE")); CharBuffer buffer = ByteBuffer.wrap(byteArray).asCharBuffer(); System.out.println(buffer.length()); // 输出5 for (int i = 0; i < buffer.length(); i++) { System.out.print(buffer.get(i)); // 输出hello,无开头空格 } }
2. 手动跳过BOM字节
如果你必须使用默认的UTF-16编码(带BOM),可以在包装ByteBuffer时跳过开头的2个BOM字节:
public static void main(String[] args) { byte[] byteArray = "hello".getBytes(Charset.forName("UTF-16")); // 跳过开头2个BOM字节,从索引2开始,长度为总长度减2 CharBuffer buffer = ByteBuffer.wrap(byteArray, 2, byteArray.length - 2).asCharBuffer(); System.out.println(buffer.length()); // 输出5 for (int i = 0; i < buffer.length(); i++) { System.out.print(buffer.get(i)); // 输出hello,无开头空格 } }
内容的提问来源于stack exchange,提问作者Peter Enns
相关产品推荐
相关产品推荐

