【问题标题】:Is UTF to EBCDIC Conversion lossless?UTF 到 EBCDIC 的转换是无损的吗?
【发布时间】:2013-05-17 17:03:04
【问题描述】:

我们有一个通过 MQ 与外部通信的进程。外部系统在大型机机器(IBM z/OS)上运行,而我们在 CentOS Linux 平台上运行我们的进程。到目前为止,我们从未遇到任何问题。

最近我们开始接收来自他们的消息,其中嵌入了不可打印的 EBCDIC 字符。他们使用字符作为压缩 ID,长度为 8 个字节。当我们收到它时,它会到达以 UTF (CCSID 1208) 编码的队列。

为了识别我们的响应消息,它们需要返回原始 8 个字节。我正在尝试在 Java 中找到一种解决方案,以便在发送响应之前将 ID 从 UTF 转换回 EBCDIC。

我一直在使用 JTOpen 库,使用 AS400Text 类进行转换。此外,交易对手已向我们发送了 ID 的快照(以字节为单位)。但是,当我比较转换后的字节时,它们与原始消息不同。

有人遇到过这个问题吗?也许我使用了错误的代码页?

感谢您的任何意见。

来自交易对手的字节数(位置 [5,14]):

00000   F0 40 D9 F0 F3 F0 CB 56--EF 80 04 C9 10 2E C4 D4  |0 R030.....I..DM|

程序输出:

UTF String: [R030ôîÕØœIDMDHP1027W 0510]
EBCDIC String: [R030ôîÃÃÂIDMDHP1027W 0510]
NATIVE CHARSET - HEX:     [52303330C3B4C3AEC395C398C29C491006444D44485031303237572030353130] 
CP500 CHARSET  - HEX:     [D9F0F3F066BE66AF663F663F623FC9102EC4D4C4C8D7F1F0F2F7E640F0F5F1F0] 

这里是一些示例代码:

private void readAndPrint(MQMessage mqMessage) throws IOException {
    mqMessage.seek(150);
    byte[] subStringBytes = new byte[32];
    mqMessage.readFully(subStringBytes);

    String msgId = toHexString(mqMessage.messageId).toUpperCase();

    System.out.println("----------------------------------------------------------------");
    System.out.println("MESSAGE_ID: " + msgId);

    String hexString = toHexString(subStringBytes).toUpperCase();
    String subStr = new String(subStringBytes);
    System.out.println("NATIVE CHARSET - HEX:     [" + hexString + "] [" + subStr + "]");

    // Transform to EBCDIC
    int codePageNumber = 37;
    String codePage = "CP037";

    AS400Text converter = new AS400Text(subStr.length(), codePageNumber);
    byte[] bytesData = converter.toBytes(subStr);
    String resultedEbcdicText = new String(bytesData, codePage);

    String hexStringEbcdic = toHexString(bytesData).toUpperCase();
    System.out.println("CP500 CHARSET  - HEX:     [" + hexStringEbcdic + "] [" + resultedEbcdicText + "]");

    System.out.println("----------------------------------------------------------------");
}

【问题讨论】:

  • new String(subStringBytes); - 这是使用您的默认编码。你知道它是什么吗?你知道它支持你可能得到的所有可能的字节组合吗?你知道它是否可逆吗?
  • 另外,“UTF”没有后缀是没有意义的。你说的是“UTF-8”吗?如果是这种情况,那么答案显然是否定的,因为并非所有字节序列在 UTF-8 中都是合法的——包括消息的前三个字节。
  • MQ 中的 CCSID 1208 对应于 UTF-8 (www-01.ibm.com/software/globalization/ccsid/…)。当您说并非所有字节序列都是合法的时,您的意思是因为 UTF-8 是可变宽度的吗?
  • 不仅是可变宽度,而且高位是有意义的(因此我喜欢维基百科页面)。您显示的“MESSAGE_ID”以C3E2 开头,这是一个无效的 UTF-8 序列:C3 是双字节序列的开头,但E2 不是有效的第二个字节;它仅作为 3 字节序列的第一个字节有效。
  • 我想再次指出new String(subStringBytes) 使用您的平台默认编码。也许这对你来说是 UTF-8,也许不是。更糟糕的是,它可能对您来说是 UTF-8,而不是在您用于部署的任何平台上的 UTF-8。

标签: java ibm-mq ebcdic


【解决方案1】:

如果 MQ 消息具有需要不同编码的不同子消息字段,那么这就是您应该处理这些消息的方式,即作为单独的消息片段。

但是正如您所描述的,整个消息需要在没有转换的情况下接收。前八个字节需要单独提取和保存。然后可以对消息的其余部分进行编码转换(除非其他子字段也需要提取为二进制、未转换的字节)。

对于任何返回消息,必须进行相反的转换。可以转换消息的文本部分,然后该子字符串可以在其前面加上原始的八个字节。然后可以通过队列将新重建的消息发送回,同样无需自动转换。

另一端的合作伙伴未正确使用消息传递产品。 (当然,您可能不应该大声说出来。)这样的消息中不应该有任何部分不能自动在两个方向上完好无损地保存下来。对于一个示例方法,它应该表示为更像是 8 字节值的 16 字节十六进制表示,而不是 8 字节二进制字段。在十六进制中,路径中的任何一种方式都不会出现转换问题。

【讨论】:

  • 我们最终进行了逐字节转换。消息被转换为 UTF-8,但随后 EBCDIC 转换丢失。我们最终使用了从 UTF-8 到 ASCII 变体的转换,然后再转换回 EBCDIC。
【解决方案2】:

在我看来,特殊的 8 个字节实际上不是 EBCDIC 字符,而只是 8 个字节的数据。如果是这种情况,那么我相信,正如另一个答案所提到的,您应该分别处理这 8 个字节,而不允许它转换为 UTF8,然后再返回 EBCDIC 进行进一步处理。

根据您使用的 EBCDIC 变体,EBCDIC 中的一个字节很可能没有转换为有意义的 UTF-8 字符,因此,您将无法通过将 UTF8 字符转换为 EBCDIC 来获取原始字节你收到。

在 Google 上简单搜索一下,我会得到几个 EBCDIC 表(例如 http://www.simotime.com/asc2ebc1.htm#AscEbcTables)。您可以看到 EBCDIC 中有很多没有分配字符的值。因此,当它们转换为 UTF8 时,您可能不会假设它们中的每一个都会转换为 Unicode 中的不同字符。因此,您提出的处理方式将非常危险且容易出错。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2020-08-23
    • 1970-01-01
    • 2016-05-31
    • 1970-01-01
    • 1970-01-01
    • 2012-05-20
    • 2014-07-16
    相关资源
    最近更新 更多