Java 为什么在Windows和Linux中从UTF-8到ISO-8859-1的转换不同?

Java 为什么在Windows和Linux中从UTF-8到ISO-8859-1的转换不同?,java,utf-8,iso-8859-1,Java,Utf 8,Iso 8859 1,我在jar文件中将以下代码从UTF-8转换为ISO-8859-1,当我在Windows中执行此jar时,我得到一个结果,在CentOS中得到另一个结果。有人知道为什么吗 public static void main(String[] args) { try { String x = "Ä, ä, É, é, Ö, ö, Ãœ, ü, ß, «, »"; Charset utf8charset = Charset.forName("UTF-8");

我在jar文件中将以下代码从UTF-8转换为ISO-8859-1,当我在Windows中执行此jar时,我得到一个结果,在CentOS中得到另一个结果。有人知道为什么吗

public static void main(String[] args) {

  try {

    String x = "Ä, ä, É, é, Ö, ö, Ü, ü, ß, «, »";

    Charset utf8charset = Charset.forName("UTF-8");
    Charset iso88591charset = Charset.forName("ISO-8859-1");

    ByteBuffer inputBuffer = ByteBuffer.wrap(x.getBytes());
    CharBuffer data = utf8charset.decode(inputBuffer);

    ByteBuffer outputBuffer = iso88591charset.encode(data);
    byte[] outputData = outputBuffer.array();

    String z = new String(outputData);

    System.out.println(z);
  }
  catch(Exception e) {
    System.out.println(e.getMessage());
  }
}
在Windows中,java-jar test.jar>test.txt创建一个包含以下内容的文件: Ä,ä,É,Ö,ö,Ü,ü,ß,«,»

但在CentOS我得到:
�?, ä, �?, é, �?, ö, �?, ü, �?, «,»

三种可能性浮现在脑海中:

  • 实际用于源代码的编码可能因平台而异
  • 编译器默认期望的编码可能因平台而异(可以在命令行中指定)
  • 调用
    x.getBytes()
    时使用的平台默认编码可能因平台而异
不清楚您试图以何种方式将UTF-8转换为ISO-8859-1,因为您的原始数据实际上只是一个
字符串。您将调用
x.getBytes()
的结果视为UTF-8编码的数据,但它只是平台默认值的一部分

同样,当你写作时:

String z = new String(outputData);
。。。这是使用平台默认编码。不要那样做

您根本不需要字节缓冲区:只需使用
text.getBytes(encoding)
进行编码,并使用
新字符串(数据,编码)
这两行进行解码

x.getBytes());

String z = new String(outputData);
是特定于平台和默认编码的


通过避免特定于平台的转换,这可以在Windows和Linux上正常运行

String x = "Ä, ä, É, é, Ö, ö, Ü, ü, ß, «, »";

Charset utf8charset = Charset.forName("UTF-8");
Charset iso88591charset = Charset.forName("ISO-8859-1");

ByteBuffer inputBuffer = ByteBuffer.wrap(x.getBytes(utf8charset));
CharBuffer data = utf8charset.decode(inputBuffer);

ByteBuffer outputBuffer = iso88591charset.encode(data);
byte[] outputData = outputBuffer.array();

String z = new String(outputData, iso88591charset);

System.out.println(z);
印刷品

Ä, ä, É, é, Ö, ö, Ü, ü, ß, «, »

在考虑输出之前,您应该首先在java中获得正确的内部表示形式的字符串。也就是说,应该是:

z.equals("Ä, ä, É, é, Ö, ö, Ü, ü, ß, «, »") == true
以上内容可以在没有任何输出编码问题的情况下进行验证,因为它只打印
true
false

在Windows中,您已经通过

ByteBuffer inputBuffer = ByteBuffer.wrap(x.getBytes());
CharBuffer data = utf8charset.decode(inputBuffer);
因为你需要从
“Ã,Ã,É,Ã,Ã-,Ã,Ã339;,ü,Ã,Ÿ,Ÿ«代码>到
“Ä,ä,É,Ö,ö,Ü,ü,ß,«代码>是:

ByteBuffer inputBuffer = ByteBuffer.wrap(x.getBytes( windows1252/*explicit windows1252 works on CentOS too*/));
CharBuffer data = utf8charset.decode(inputBuffer);
在此之后,使用ISO-8859-1执行一些操作,这是徒劳的,因为原始字符串中只有一半的字符 可以在ISO-8859-1中表示,更不用说您已经按照上述要求完成了。您可以在
utf8charset.decode(inputBuffer)

因此,现在您的代码可以如下所示:

String x = "Ä, ä, É, é, Ö, ö, Ü, ü, ß, «, »";

Charset windows1252 = Charset.forName("Windows-1252");
Charset utf8charset = Charset.forName("UTF-8");

byte[] bytes = x.getBytes(windows1252);
String z = new String(bytes, utf8charset);

                                //Still wondering why you didn't just have this literal to begin with
                                //Check that the strings are internally equal so you know at least that
                                //the code is working

System.out.println(z.equals( "Ä, ä, É, é, Ö, ö, Ü, ü, ß, «, »")); 
System.out.println(z);

这个� 字符表示无法打印的字符(请参阅)。也许您的CentOS编码与Windows不同?您真正想做的是什么?为什么你有
“Ã,Ã,É,Ã,è,Ã339;,ü,Ã376;«,û”需要转换,如果您可以只使用根本不需要转换的
“Ä,ä,É,Ö,ö,Ü,ß,ß,«,»”
?如果这些不是源文件中的字符串文字,那么您需要提供更多详细信息。对不起,这段代码的意义是什么?您已经开始使用正确的最终结果,而代码完全没有任何用处。它与
System.out.println(x)完全相同在声明
x
@Esailija之后,最好询问OP。代码以前后编码为两种不同编码的字符开始。唯一的区别是,他有一个伪加密字符串,当使用默认编码的getBytes()调用该字符串时,可以使用UTF-8进行解码。这显然取决于平台。@Esailija:可能字节在应用程序之间传输。这可能只是在单个应用程序中演示同一问题的示例代码。@RemyLebeau我不明白,这个答案完全没有说明什么。它有一个字符串文本,然后被编码为utf-8,结果被解码回utf-8。也就是说,什么都不做。在此之后,重复相同的过程,但使用ISO-8859-1。同样,完全不操作(最多此操作会导致信息丢失,但是)。没有操作不是特定于平台的。:P无论如何,我通常在javascript室,如果你想有时间讨论这个问题的话。