我有一个简单的测试
@Test
public void utf16SizeTest() throws Exception {
final String test = "п";
// 'п' = U+043F according to unicode table
// 43F to binary = 0100 0011 1111 (length is 11)
// ADD '0' so length should be = 16
// 0000 0100 0011 1111
// 00000100(2) 00111111(2)
// 4(10) 63(10)
final byte[] bytes = test.getBytes("UTF-16");
for (byte aByte : bytes) {
System.out.println(aByte);
}
}
如您所见,我首先将'п'转换为二进制,然后在length != 16
时添加尽可能多的空位。
期望输出为4 , 63
但是实际的是:
-2
-1
4
63
我在做什么错了?
答案 0 :(得分:6)
如果您尝试:
final String test = "ппп";
您会发现-2 -1
仅出现在开头:
-2
-1
4
63
4
63
4
63
-2是0xFE
,-1是0xFF
。它们一起形成BOM (Byte_order_mark)
:
在UTF-16中,可以将BOM(U + FEFF)放置为 文件或字符流,以指示文件的字节序(字节顺序) 文件或流的所有16位代码单元。如果尝试 要以错误的字节序读取此流,字节将是 交换,从而提供字符U + FFFE,该字符由 Unicode作为“非字符”,永远不应出现在文本中。
test.getBytes("UTF-16");
在对字节进行编码时默认使用Big Endian,因此BOM包含在前面,以便以后的处理器可以知道使用了Big Endian。
您可以改为使用UTF-16LE
or UTF-16BE
来显式指定字节序,从而避免在输出中使用BOM:
final byte[] bytes = test.getBytes("UTF-16BE");
UTF-16
字符集使用16位数字,因此对字节顺序敏感。在这些编码中,流的字节顺序可以由以Unicode字符'\uFEFF'
表示的初始字节顺序标记表示。字节顺序标记的处理方式如下:
在解码时,
UTF-16BE
和UTF-16LE
字符集将初始字节顺序标记解释为ZERO-WIDTH NON-BREAKING SPACE
; 编码时,它们不会写字节顺序标记。在解码时,
UTF-16
字符集解释输入流开头的字节顺序标记以指示流的字节顺序,但如果没有字节顺序,则默认为big-endian。订单标记; 编码时,它使用big-endian字节顺序并写入一个big-endian字节顺序标记。