为什么String.getBytes()在编译的jar中表现不同?

时间:2014-07-17 13:15:08

标签: java encoding

我有一个项目,它从以latin1编码的纯文本文件中读取数据,然后将其发送到使用UTF-8编码的MySQL数据库。 在早期版本的一些遗留代码中,使用new String(String.getBytes("UTF-8"))手动重新编码文件中已正确读取的字符串。这在Eclipse中运行良好,但出于某种原因,在将其编译为可执行文件.jar之后,这导致使用latin1编码发送字符串,尽管明确地将JDBC定义为UTF-8编码。 删除不必要的转换后,它在IDE和编译的jar中都能正常工作。

我想知道可能导致这种情况的原因。 jar和IDE是在同一个系统上执行的,除非Eclipse添加了一些我不知道的VM设置相同的设置。此行为在其他计算机上也以完全相同的方式可见。

2 个答案:

答案 0 :(得分:1)

有两个问题:

new String(String.getBytes("UTF-8"))

采用默认系统编码来创建新String。您应该始终明确指定新字符串的编码,例如

new String(String.getBytes("UTF-8"), "UTF-8")

其他系统上的默认编码很可能不同,导致字符集转换(例如从UTF-8到Cp1252)。

您应用的转换仅在字符串被错误读取且目标字符集与源字符集不同时才相关。例如:您最初读取的某些字节为Cp1252,但是您需要将其转换为另一个字符集(例如Cp1250)。然后你会这样做:

new String(String.getBytes("Cp1252"), "Cp1250")

这会将字符串中的字符转换为Cp1252中的字节,然后取出字节并在Cp1250中解释它们。对于某些(但不是全部)字符,这将映射到相同的字符,但其他字符将被重新映射。

如果您在问题中已经正确阅读了字符串,那么这样做完全没有意义。在Java内部,字符串只是一个字符数组,只有当字节数据(或从字节数据读取)持久存在时才是相关的编码。

答案 1 :(得分:1)

这一行:

new String(String.getBytes("UTF-8"))

没有实现任何类型的重新编码。它的作用是将字符串转换为字节数组,使用UTF-8编码,然后使用默认编码从中构造一个新字符串。结果又是一个String,Java中的字符串没有相关的编码:根据规范它们包含char s,它们是UTF-16代码点。没有定义字节级编码。该行代码可以执行的最佳检索完全相同的字符串,如果默认编码不匹配,则结果将是一个损坏的字符串。

如果您对数据库使用了错误的编码问题,则必须在JDBC级别上执行操作,确保通过线路发送的字符串已正确编码。