Java编译平台文件编码问题

这是我发布堆栈溢出的第一篇文章。 我从1998年开始做Java,所以我不是初学者。 最近我遇到了一个我记不起来的文件字符编码问题。 在不同平台上运行时,必须了解文本文件的字符编码和编写正确处理编码的代码是很常见的。 但我发现的问题是由与执行平台不同的平台上的编译引起的。 这完全出乎意料,因为根据我的经验,当javac创建一个类文件时,重要的参数是java源和目标params,以及进行编译的JDK的版本。 我的情况是,在Mac OS X上使用JDK 1.6.0_22编译的类与在Linux上运行时使用1.6.0_23-b05编译的类不同,在Mac OS X上运行时。指定的源和目标是1.4。

使用PrintStream println方法将在内存中编码为ISO-8859_1的String写入磁盘。 根据Java代码编译的平​​台,字符串的编写方式不同。 这导致了一个错误。 该错误的修复是在编写和读取文件时明确指定文件编码。

让我感到惊讶的是,行为的不同取决于编译类的位置,而不是运行类的平台。 我非常熟悉Java代码在不同平台上运行时的行为方式。 但是,当在不同平台上编译的相同代码在同一平台上以不同方式运行时,它有点可怕。

有没有人遇到过这个具体问题? 对于在没有明确指定字符编码的情况下读取和写入字符串到文件的任何Java代码,似乎都不适用。 这种情况经常发生多少次?

谢谢,

Richard Brewster http://rabbitsoftware.com

没有像在内存中编码为ISO-8859-1的String这样的东西。 内存中的Java字符串始终是Unicode字符串。 (用UTF-16编码,但你现在不需要这个)。

当您输入或输出字符串时,编码仅在播放时 – 然后,在没有显式编码的情况下,它使用系统默认值(在某些系统上取决于用户设置)。

正如McDowell所说,源文件的实际编码应该与编译器假定的源文件编码匹配,否则会出现问题。 你可以通过几种方式实现这一目标:

  • 使用编译器的-encoding选项,给出源文件的编码。 (使用ant,您可以设置encoding=参数。)
  • 使用编辑器或任何其他工具(如recode )将文件的编码更改为编译器默认值。
  • 使用native2ascii (使用右侧-encoding选项)使用\uXXXX -escapes将源文件转换为ASCII。

在最后一种情况下,您稍后可以使用每个默认编码在任何地方编译此文件,因此如果您将源代码提供给编码 – 不知情的人在某处编译,这可能是要走的路。

如果你有一个由多个文件组成的更大的项目,它们都应该具有相同的编码,因为编译器只有一个这样的开关,而不是几个。

在我过去几年的所有项目中,我总是用UTF-8编码所有文件,并在我的ant buildfile中为javac任务设置encoding="utf-8"参数。 (我的编辑器非常聪明,能够自动识别编码,但我将默认值设置为UTF-8。)

编码对其他源代码处理工具很重要,比如javadoc。 (在那里你还应该输出-charset-docencoding选项 – 它们应该匹配,但可以与source- -encoding不同。)

我猜测在编译阶段存在转码问题,编译器缺乏源文件编码的方向(例如,请参阅javac -encoding开关)。

编译器通常使用系统默认编码,如果您不具体,可能导致字符串和字符文字被破坏(内部,Java字节码使用修改的UTF-8格式,因此二进制文件是可移植的)。 这是我能想象在编译时引入问题的唯一方法。

我在这里写了一些关于此的内容。

在使用数学公式时,使用不是ascii(Σ,σ,Δ等)的变量名时,我遇到了类似的问题。 在linux上,它在解释时使用了UTF-8编码。 在Windows上,它抱怨名称无效,因为Windows使用ISO-LATIN-1。 解决方案是在我用来编译这些文件的ant脚本中指定编码。

始终在源文件中使用转义码(例如\uxxxx ),这不会有问题。 @Paulo提到了这一点,但我想明确地说出来。