这个主题已成为许多讨论的目标,但我们仍然看到新的主题出现。 我的场景如下:
在 Linux 服务器上运行的 Java 框架,其中 UTF-8 是 JVM 中的默认字符编码。该框架由一些接收要处理的 Tibco RV 消息的服务组成。其中一些消息包含非 ASCII 字符并从 Windows 服务器发送,ISO8859-1 是创建消息时使用的编码。 现在,当从 Tib rv 消息中提取数据时,有问题的字段作为 Java 对象“到达”,需要转换为字符串......在这里,我还无法提取包含非 ISO8859-1 字符串以正确的方式将 ASCII 字符(瑞典语“å”、“ä”、“ö”)转换为 UTF-8 字符串。 我尝试过使用以下方法:
String isoStreet = new String(response.get("street").toString().getBytes(StandardCharsets.ISO_8859_1),java.nio.charset.StandardCharsets.UTF_8);
我也尝试过使用 java.nio 包中的编码器/解码器,但没有成功。
同样有趣的是,我使用 PuttY 连接到托管并运行服务的服务器。从那里我可以从 shell 发出直接的 Tibco rv 请求(使用 tibcorvsend 客户端),并且似乎我需要在登录之前在 PuttY (Window_>Translation) 中将远程字符集设置为 ISO8859-1服务器并发出 Tib rv 请求 - 完成此操作后,无论我在远程 Linux 服务器中设置什么编码,这些非 ASCII 字符都会在响应中正确显示。 在这种情况下,使用“export LC_ALL=en_US.UTF-8”或“export LC_ALL=sv_SE.iso88591”并不重要...只有我在 PuttY 中设置的远程编码...
这应该意味着响应消息看起来不错,并且至少 shell 能够输出正确的字符。但是,当在 Java VM 内部(使用 Java 服务)时,我猜想在 Watch View 中调试和查看响应对象(不希望将其转换为字符串)时,响应字段会悄悄地插入字符串中...不确定您是否可以关注我,如果没有,我可能会在需要时尝试更清楚......
任何人对此问题的任何意见
问候 /R
最佳答案
一个character encoding指定如何将由字符组成的文本转换为字节,反之亦然。如您所知,有不同的字符编码,例如 ASCII、ISO-8859-1 和 UTF-8。
字符串由字符组成。在某些时候,您希望将这些字符转换为字节,以便可以通过网络发送它们、将它们存储在文件中或执行任何您想要执行的操作。您使用字符编码将字符串转换为字节。在另一端,您接收字节时,使用相同的字符编码将字节转换回字符串中的字符。
让我们看看为什么像您发布的那样的行是不正确的。让我们首先重写它,以便我可以解释各个部分:
String street = response.get("street").toString();
byte[] streetBytes = street.getBytes(StandardCharsets.ISO_8859_1);
String isoStreet = new String(streetBytes, StandardCharsets.UTF_8);
在第一行中,您从响应中获取一些数据并将其转换为字符串。 (response.get("street")
返回什么?)。
在第二行中,您使用 ISO-8859-1 字符集对该字符串进行编码。您将获得一个字节数组,其中包含字符串中字符的有效 ISO-8859-1 字符代码。
在第三行中,您将字节转换为字符串,并假设这些字节是 UTF-8 字节。这显然是错误的,因为字节是 ISO-8859-1 数据而不是 UTF-8 数据。当您这样做时,您可能会得到错误的字符,如果字节数组包含的字节序列根据 UTF-8 不是有效字符,甚至会出现异常。
需要注意的一件事是字符串仅由字符组成。字符串本身没有编码。您可以使用字符编码将字符串转换为字节,反之亦然。您不能“更改字符串的字符编码”,因为字符编码根本不是字符串的属性。就像数字本质上不是十进制或十六进制一样 - 这些只是表示同一数字的不同方式。
你需要做的是:
在编写消息时,请确保使用正确的字符编码将字符串转换为字节。
在阅读消息时,请确保使用正确的字符编码将字节转换为字符串。
不要使用平台的默认字符编码将某些内容读入字符串,然后尝试“转换字符串”。那是行不通的。
关于Java 字符编码、ISO 到 UTF 转换,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/28479462/