Java 为什么使用链字节[]→ 一串→ 字节[]使用UTF-8字符集时输入和输出不同?

Java 为什么使用链字节[]→ 一串→ 字节[]使用UTF-8字符集时输入和输出不同?,java,utf-8,character-encoding,data-conversion,Java,Utf 8,Character Encoding,Data Conversion,以下测试失败 @Test public void testConversions() { final Charset charset = Charsets.UTF_8; final byte[] inputBytes = {37, 80, 68, 70, 45, 49, 46, 52, 13, 10, 37, -11, -28, -10, -4, 13, 10}; final String string = new String(inputBytes, charset);

以下测试失败

@Test
public void testConversions() {
    final Charset charset = Charsets.UTF_8;
    final byte[] inputBytes = {37, 80, 68, 70, 45, 49, 46, 52, 13, 10, 37, -11, -28, -10, -4, 13, 10};
    final String string = new String(inputBytes, charset);
    final byte[] outputBytes = string.getBytes(charset);
    assertArrayEquals(inputBytes, outputBytes);
}
如果使用的不是UTF-8字符集ISO_8859_1,则测试通过,即使使用更大的inputBytes数组。输入和输出是否因UTF-8的“可变宽度”特性而不同

附加问题:转换字节[]是否是一个真实的假设→ 一串→ 如果使用ISO_8859_1,字节[]将始终具有相同的输入和输出字节数组

输入和输出是否因UTF-8的“可变宽度”特性而不同

它们的不同之处在于,由于可变宽度编码,并非所有字节序列都将出现在有效的UTF-8编码字符串中

您可以在以下列表中看到这一点:

1字节:0xxxxxxx 2字节:110xxxxx 10xxxxxx 3字节:1110xxxx 10xxxxxx 10xxxxxx 4字节:11110xxx 10xxxxxx 10xxxxxx 10xxxxxx xs显示可以任意为0或1的位;数字显示在有效编码中必须设置为该值的位

因此,在有效的UTF-8字符串中永远找不到例如11000000 11000000。如果您试图从这些字节构建字符串,字符编码将执行。。。有些事

[new Stringbyte[],Charset]始终使用此字符集的默认替换字符串替换格式错误的输入和不可映射的字符序列

因此,您构建的字符串不一定能够映射回输入

奖金问题

是的,因为它是固定宽度编码,所有可能的字节都有一个对应的字符

没有很好的理由尝试将字节[]直接转换为字符串,除非您知道它是要恢复的字符串的有效编码,并且您知道用于编码它的字符集,或者您怀疑它是字符串,并且您想尝试恢复其内容

如果您想通过需要发送字符串的某个通道传输字节[],请使用以下命令

输入和输出是否因UTF-8的“可变宽度”特性而不同

它们的不同之处在于,由于可变宽度编码,并非所有字节序列都将出现在有效的UTF-8编码字符串中

您可以在以下列表中看到这一点:

1字节:0xxxxxxx 2字节:110xxxxx 10xxxxxx 3字节:1110xxxx 10xxxxxx 10xxxxxx 4字节:11110xxx 10xxxxxx 10xxxxxx 10xxxxxx xs显示可以任意为0或1的位;数字显示在有效编码中必须设置为该值的位

因此,在有效的UTF-8字符串中永远找不到例如11000000 11000000。如果您试图从这些字节构建字符串,字符编码将执行。。。有些事

[new Stringbyte[],Charset]始终使用此字符集的默认替换字符串替换格式错误的输入和不可映射的字符序列

因此,您构建的字符串不一定能够映射回输入

奖金问题

是的,因为它是固定宽度编码,所有可能的字节都有一个对应的字符

没有很好的理由尝试将字节[]直接转换为字符串,除非您知道它是要恢复的字符串的有效编码,并且您知道用于编码它的字符集,或者您怀疑它是字符串,并且您想尝试恢复其内容

如果您想通过需要发送字符串的某个通道传输字节[],请使用以下命令

附加问题:转换字节[]是否是一个真实的假设→ 一串→ 如果使用ISO_8859_1,字节[]将始终具有相同的输入和输出字节数组

对。将唯一字符映射到每个字节的任何单字节字符集将在往返转换中保留所有字节值。从1987年起,ISO 8859 1对每个单字节值都有一个唯一的映射

而CP1252 Windows Latin 1(Windows上常见的默认字符集)有5个字节的值,没有字符映射到该值。因此,如果使用cp1252进行往返转换,平均每256个字节会丢失5个字节,或大约2%的数据

附加问题:转换字节[]是否是一个真实的假设→ 一串→ 如果使用ISO_8859_1,字节[]将始终具有相同的输入和输出字节数组

对。将唯一字符映射到每个字节的任何单字节字符集将在往返转换中保留所有字节值。从1987年起,ISO 8859 1对每个单字节值都有一个唯一的映射


而CP1252 Windows Latin 1(Windows上常见的默认字符集)有5个字节的值,没有字符映射到该值。因此,如果您使用cp1252进行往返转换,平均每256个字节会丢失5个字节,或大约2%的数据

明白了!非常感谢您如此详细的解释!:关于base64的建议将非常有用。再次感谢!有一种替代方法可以始终替换格式错误的输入和取消映射
可编程字符序列:例外!期望使用一种编码并获得不匹配的字节肯定是例外。接收代码错误或数据损坏几乎肯定是由发送代码造成的,而不是由传输或存储问题造成的。如果您以抛出异常的方式使用字符编码-解码类,您会更快地发现错误。如果你仍然想在一些比没有好的理论上传递损坏的文本,那么你可以在异常处理程序中这样做。明白了!非常感谢您如此详细的解释!:关于base64的建议将非常有用。再次感谢!有一种替代方法可以始终替换格式错误的输入和不可映射的字符序列:异常!期望使用一种编码并获得不匹配的字节肯定是例外。接收代码错误或数据损坏几乎肯定是由发送代码造成的,而不是由传输或存储问题造成的。如果您以抛出异常的方式使用字符编码-解码类,您会更快地发现错误。如果您仍然希望根据“有些比没有好”的理论传递损坏的文本,那么您可以在异常处理程序中这样做。