Java编译器平台文件编码问题

Java编译器平台文件编码问题,java,character-encoding,javac,Java,Character Encoding,Javac,最近,我遇到了一个文件字符编码问题,我不记得曾经遇到过这个问题。在不同的平台上运行时,必须了解文本文件的字符编码并编写正确处理编码的代码是很常见的。但是我发现的问题是由编译引起的,编译是在不同于执行平台的平台上进行的。这完全出乎意料,因为根据我的经验,在javac创建类文件时,重要的参数是java源和目标参数,以及执行编译的JDK版本。在我的案例中,当在Mac OS X上运行时,在Mac OS X上使用JDK 1.6.0_22编译的类与在Linux上使用1.6.0_23-b05编译的类表现不同。

最近,我遇到了一个文件字符编码问题,我不记得曾经遇到过这个问题。在不同的平台上运行时,必须了解文本文件的字符编码并编写正确处理编码的代码是很常见的。但是我发现的问题是由编译引起的,编译是在不同于执行平台的平台上进行的。这完全出乎意料,因为根据我的经验,在javac创建类文件时,重要的参数是java源和目标参数,以及执行编译的JDK版本。在我的案例中,当在Mac OS X上运行时,在Mac OS X上使用JDK 1.6.0_22编译的类与在Linux上使用1.6.0_23-b05编译的类表现不同。指定的源和目标是1.4

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

令我惊讶的是,行为的不同取决于类的编译位置,而不是运行该类的平台。我非常熟悉Java代码在不同平台上运行时的不同行为。但是,当在不同平台上编译的相同代码在相同平台上运行时,会有点可怕


有没有人遇到过这个具体问题?对于任何在文件中读写字符串而不显式指定字符编码的Java代码来说,这似乎是一个不好的预兆。多久完成一次?

我猜在编译阶段存在代码转换问题,并且编译器缺乏对源文件编码的指导(例如,请参阅javac开关)

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


关于这一点,我已经写了一点。

内存中没有像编码为ISO-8859-1的字符串这样的东西。内存中的Java字符串始终是Unicode字符串。(在UTF-16中编码(从2011年开始——我认为它在以后的Java版本中发生了变化),但您现在真的不需要这样做)


只有当您输入或输出字符串时,编码才起作用-然后,如果没有显式编码,它将使用系统默认值(在某些系统上,这取决于用户设置)

正如McDowell所说,源文件的实际编码应该与编译器对源文件所采用的编码相匹配,否则就会出现问题。您可以通过以下几种方式实现此目的:

  • 使用编译器的
    -encoding
    选项,给出源文件的编码。(使用ant,您可以设置
    encoding=
    参数。)
  • 使用编辑器或任何其他工具(如
    recode
    )将文件编码更改为编译器默认值
  • 使用
    native2ascii
    (使用右侧的
    -encoding
    选项)使用
    \uxxx
    -escapes将源文件转换为ASCII
在最后一种情况下,您以后可以使用每个默认编码在任何地方编译此文件,因此,如果您将源代码提供给不知道编码的人,以便在某个地方编译,那么这可能是一种方法

如果您有一个包含多个文件的较大项目,那么它们都应该具有相同的编码,因为编译器只有一个这样的开关,而不是几个

在过去几年的所有项目中,我总是用UTF-8编码我的所有文件,并且在我的ant构建文件中,将
encoding=“UTF-8”
参数设置为javac任务。(我的编辑器足够智能,可以自动识别编码,但我将默认设置为UTF-8。)


编码对于其他源代码处理工具很重要,比如javadoc。(在这里,您还应该为输出添加
-charset
-docencoding
选项-它们应该匹配,但可能不同于源代码-
-encoding

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

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

有问题的文件编码为utf-8吗?源代码中是否存在有问题的字符,或者这些字符仅在该特定机器上编译后无效?是否使用静态final将其编译到类中(编译静态final将字符串“烘焙”到类中)?或者,当您说写入磁盘时,您是在序列化数据吗?序列化类实例?使用默认(即编译平台)编码编译序列化方法?@Steve B:事实上,所有字符串文本和其他编译时常量字符串都“烘焙”到类中,而不仅仅是静态的最终字符串。很好,我认为通常人们会编写
Sigma
(或
sum
),
Sigma
delta
等等,而不是使用正确的希腊字母。我曾经创建了一个名为
。我想称之为
ℕ₀,但javac不接受这一点,因为
不是Java的数字。@Paŭlo Ebermann我遇到的问题是变量太多,方程太复杂了,所以文档是一个PITA。我使用了特殊字符和文件/cor证明