ISO-8859-1编码和二进制数据保存

我读了@Esailija对我的一个问题的评论

ISO-8859-1是唯一完全保留原始二进制数据的编码,具有精确的字节代码点匹配

我也在@AaronDigulla的回答中读到:

在Java中,ISO-8859-1(又名ISO-Latin1)是1:1映射

我需要对此有所了解。 这将失败(如此处所示):

// \u00F6 is ö System.out.println(Arrays.toString("\u00F6".getBytes("utf-8"))); // prints [-61, -74] System.out.println(Arrays.toString("\u00F6".getBytes("ISO-8859-1"))); // prints [-10] 

问题

  1. 我承认我不太明白 – 为什么它没有得到上面代码中的字节
  2. 最重要的是,指定的位置ISO-8859-1 字节保留行为 ) – 链接到源,或者JSL会很好。 它是唯一具有此属性的编码吗?
  3. 它与ISO-8859-1是默认默认值有关吗?

另请参阅此问题以获取其他字符集中的反例。

"\u00F6"不是字节数组。 它是一个包含单个字符的字符串。 改为执行以下测试:

 public static void main(String[] args) throws Exception { byte[] b = new byte[] {(byte) 0x00, (byte) 0xf6}; String s = new String(b, "ISO-8859-1"); // decoding byte[] b2 = s.getBytes("ISO-8859-1"); // encoding System.out.println("Are the bytes equal : " + Arrays.equals(b, b2)); // true } 

要检查这是否适用于任何字节,只需通过所有字节改进代码:

 public static void main(String[] args) throws Exception { byte[] b = new byte[256]; for (int i = 0; i < b.length; i++) { b[i] = (byte) i; } String s = new String(b, "ISO-8859-1"); byte[] b2 = s.getBytes("ISO-8859-1"); System.out.println("Are the bytes equal : " + Arrays.equals(b, b2)); } 

ISO-8859-1是标准编码。 所以使用的语言(Java,C#或其他)并不重要。

这是一个维基百科参考 ,声称每个字节都包括在内:

1992年,IANA注册了字符映射ISO_8859-1:1987,更常见的是其首选的MIME名称ISO-8859-1(请注意ISO 8859-1的额外连字符),ISO 8859-1的超集,在互联网上使用。 此映射将C0和C1控制字符分配给未分配的代码值, 从而通过每个可能的8位值提供256个字符。

(强调我的)

对于保留原始二进制数据的编码,需要将每个唯一字节序列映射到唯一字符序列。

这排除了所有多字节编码(UTF-8/16/32,Shift-Jis,Big5等),因为并非每个字节序列都有效,因此会解码为某些替换字符(通常是?或 )。 没有办法从字符串中分辨出在解码后导致替换字符的原因。

另一种选择是忽略无效字节,但这也意味着无限不同的字节序列解码为相同的字符串。 您可以使用字符串中的hex编码替换无效字节,如"0xFF" 。 没有办法判断原始字节是否合法地解码为"0xFF"因此也不起作用。

这留下了8位编码,其中每个序列只是一个字节。 如果存在映射,则单个字节有效。 但是许多8位编码都有漏洞,不能编码256个不同的字符。

要保留原始二进制数据,您需要编码256个不同字符的8位编码。 ISO-8859-1在这方面并不是唯一的。 但它的独特之处在于,解码后的代码点的值也是从中解码的字节值。

所以你有解码的字符串和编码的字节,然后它总是

 (byte)str.charAt(i) == bytes[i] 

对于任意二进制数据,其中strnew String(bytes, "ISO-8859-1")bytesbyte[]


它也与Java无关。 我不知道他的评论意味着什么,这些是字符编码的属性而不是编程语言。