1

我正在调试一个第三方网关系统,它将二进制消息转换为 XML Web 服务。当它接收到包含特殊字符 0x80、0x81、0x82 和 0x83 的消息时会出现问题,它们没有正确地作为 XML 发送。

我已将问题范围缩小到他们将 byte[] 转换为 String 的位置,并制作了一个简单的示例来说明问题所在。特殊值都被翻译成相同的“未知”字符。

public static void main(String[] args) {
    test(0x80);test(0x81);test(0x82);test(0x83);
}
public static void test(int value) {
    String message = new String(new byte[]{(byte)value});
    System.out.println(value + " => " + message + " => " + Arrays.toString(message.getBytes()));
}

输出

128 => � => [-17, -65, -67]
129 => � => [-17, -65, -67]
130 => � => [-17, -65, -67]
131 => � => [-17, -65, -67]

我想知道这应该如何解决。我尝试更改他们的代码以使用显式字符集

new String(bytes, Charset.forName("UTF-8"))

然而,这会导致同样的问题。值 0x80-0x83 似乎不作为有效的 XML 实体存在。

我发现你可以使用哪种工作的字符构造函数,但翻译以下内容,我不确定这是否正确?

new String(new char[]{(char) value}, 0, 1); 

输出

128 => weird box character 0080 => [-62, -128]
129 => weird box character 0081 => [-62, -127]
130 => weird box character 0082 => [-62, -126]
131 => weird box character 0083 => [-62, -125]
4

3 回答 3

1

您不能按字节将字节转换为 Java 字符串。您必须考虑二进制数据的编码。例如,UTF-8 每个字符可以有不同的字节长度。

请参阅UTF-8 和 Unicode,0xC0 和 0x80 是什么?

于 2013-06-04T12:23:51.720 回答
1

您不能直接在 XML 文档中传输二进制数据——例如,没有有效的方法来设置 ASCII 零。

您需要将其编码为 ASCII 字符串(base64 或类似字符串)并进行传输,然后在接收端对其进行取消编码。

于 2013-06-04T12:26:52.800 回答
0

首先,使用

String message = new String(new byte[]{(byte)value});

几乎总是错误的。要转换byte[]String您必须决定使用哪种字符编码。上面的代码将(不幸地)使用 JVM 默认编码进行转换,这取决于各种操作系统设置(如果用户更改这些设置,可能随时更改)。在几乎所有情况下,您都希望明确指定编码。

现在解决您的问题:

我想知道这应该如何解决。我尝试更改他们的代码以使用显式字符集

new String(bytes, Charset.forName("UTF-8"))

然而,这会导致同样的问题。

这很正常。您告诉 Java 将单字节序列“0x80”解释为 UTF-8。但是,这不是有效的 UTF-8 字符串。因此 Java 使用Unicode 替换字符来指示错误。

要解决这个问题,你必须在你得到的数据中找出“0x80”等是什么意思。找出数据使用的字符编码,并使用该编码转换为String.


作为猜测:数据可能使用 Windows 编码 CP 1252(通常与 ISO 8859-1 混合)。在 CP 1252 中,0x80 是欧元字符。

于 2013-06-04T14:26:12.257 回答