在Linux更新后,JVM中的文件编码错误

3

在更新了Linux和Java(1.6.0.13-> 1.6.0.45)之后,Java进程使用不同的文件编码(系统属性文件编码)

新的操作系统版本。不幸的是,我不再知道以前的版本。但我可以告诉你,更新出了问题。我的同事首先使用x32操作系统版本进行更新,然后我们重新安装了x64版本。

>uname -a
Linux <hostname> 2.6.31.5-0.1-desktop #1 SMP PREEMPT 2009-10-26 15:49:03 +0100 x86_64 x86_64 x86_64 GNU/Linux

本地设置

>locale
LANG=en_US.ISO8859-1
LC_CTYPE=en_US.ISO8859-1
LC_NUMERIC="en_US.ISO8859-1"
LC_TIME="en_US.ISO8859-1"
LC_COLLATE="en_US.ISO8859-1"
LC_MONETARY="en_US.ISO8859-1"
LC_MESSAGES="en_US.ISO8859-1"
LC_PAPER="en_US.ISO8859-1"
LC_NAME="en_US.ISO8859-1"
LC_ADDRESS="en_US.ISO8859-1"
LC_TELEPHONE="en_US.ISO8859-1"
LC_MEASUREMENT="en_US.ISO8859-1"
LC_IDENTIFICATION="en_US.ISO8859-1"
LC_ALL=

测试程序

public class Test
{
  public static void main(String[] args)
  {
    System.out.println(System.getProperty("file.encoding"));
  }
}

如果我启动这个测试程序,它会返回ANSI_X3.4-1968。在其他设置相同的机器上,它会返回ISO8859-1。即使我使用显式环境变量启动它,它仍然保持不变。唯一有效的解决方案是使用-Dfile.encoding选项。但我不想调整使用Java(Tomcat、Maven、Ant、Hudson等)的所有脚本。我想恢复旧的行为,即从系统区域设置中检索Java程序的文件编码。
>java Test
ANSI_X3.4-1968

>LANG=de_DE.ISO8859-1 java Test
ANSI_X3.4-1968

>java -Dfile.encoding=ISO8859-1 Test
ISO8859-1

至少C程序使用正确的编码,而不是使用ANSI_X3.4-1968。

>idn --debug  --quiet "a.de"
Charset `ISO-8859-1'.
....

有没有人知道,在操作系统或Java更新期间是否会丢失任何JVM特定设置。

感谢任何帮助。


作为最后的手段,可以使用Java配置文件/环境变量(JAVA_OPTS),它们会在每次JVM启动时自动读取和应用。如果您无法找到并恢复原始编码,您可以通过这种方式为所有Java应用程序“永久”设置它。 - icza
你能否更具体地说明一下Java配置文件?我不知道有哪些。JAVA_OPS似乎不起作用。 export JAVA_OPTS=-Dfile.encoding=ISO-8859-15 java Test ANSI_X3.4-1968。这对于javac编译器设置无效,它也使用ANSI编码。 - tejoe
我不知道Linux配置文件的位置,因为我使用Windows。有关JAVA_OPTS,请参见https://dev59.com/Z3I-5IYBdhLWcg3wHUdB。 - icza
2个回答

5

刚在Debian上遇到了类似的问题。这是由于默认的LANG/LC设置为未在/etc/locale.gen中配置的语言环境所导致。

要解决此问题,您需要取消注释/etc/locale.gen中的相应行,并运行sudo locale-gen命令。

我很惊讶Java没有任何关于这个问题的警告。例如,Perl会大声告诉您发生了故障:

$ LANG=pl_PL.UTF-8 perl -e ''                
perl: warning: Setting locale failed.
perl: warning: Please check that your locale settings:
    LANGUAGE = "en_GB:en",
    LC_ALL = (unset),
    LANG = "pl_PL.UTF-8"
    are supported and installed on your system.
perl: warning: Falling back to the standard locale ("C").

此外,为了解释一些其他行为:ANSI_X3.4-1968只是官方(而且有点不透明)地表示“ASCII”的方式,“ISO-8859.1”是“通常”的8位ASCII超集,它被称为各种名称,包括“西方”或“Latin 1”,在操作系统如DOS或旧版本的Windows中,它是最接近“标准”字符集的东西。

5
感谢icza的帮助。我在谷歌上搜索了一下JAVA_OPTS,并发现应该使用JAVA_TOOL_OPTIONS。 请参见如何使用JAVA_OPTS环境变量? 或者使用_JAVA_OPTIONS: 使用JAVA_OPTS env变量运行java 两者都可以很好地工作,用于运行时和编译器。
>export JAVA_TOOL_OPTIONS=-Dfile.encoding=ISO8859-1
>java Test
Picked up JAVA_TOOL_OPTIONS: -Dfile.encoding=ISO8859-1
ISO8859-1

>javac Test.java
Picked up JAVA_TOOL_OPTIONS: -Dfile.encoding=ISO8859-1

>export _JAVA_OPTIONS=-Dfile.encoding=ISO8859-1
>java Test
Picked up _JAVA_OPTIONS: -Dfile.encoding=ISO8859-1
ISO8859-1

>javac Test.java
Picked up _JAVA_OPTIONS: -Dfile.encoding=ISO8859-1

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接