2011-02-07 61 views
8

這是我第一篇文章,堆棧溢出。自1998年以來我一直在做Java,所以我不是初學者。最近我遇到了一個我不記得遇到過的文件字符編碼問題。在不同平臺上運行時,必須瞭解文本文件的字符編碼以及編寫能夠正確處理編碼的代碼是很常見的。但是我發現的問題是由與執行平臺不同的平臺上的編譯造成的。這完全是出乎意料的,因爲根據我的經驗,當javac創建一個類文件時,重要的參數是java源和目標參數,以及執行編譯的JDK版本。我的情況是,在Mac OS X上使用JDK 1.6.0_22編譯的類與在Linux上使用1.6.0_23-b05編譯的類的行爲不同,在Mac OS X上運行時。指定的源和目標爲1.4。Java編譯器平臺文件編碼問題

在內存中編碼爲ISO-8859_1的字符串使用PrintStream println方法寫入磁盤。根據Java代碼編譯的平​​臺,字符串的寫法不同。這導致了一個錯誤。該錯誤的修復是在寫入和讀取文件時明確指定文件編碼。

讓我感到驚訝的是,行爲不同,取決於類的編譯位置,而不是在哪個平臺上運行。我非常熟悉Java代碼在不同平臺上運行時的行爲不同。但是當編碼在不同平臺上的相同代碼在相同平臺上以不同方式在相同平臺上運行時有點可怕。

有沒有人遇到過這個問題?對於任何讀取和寫入字符串的Java代碼,如果沒有明確指定字符編碼,它似乎都會生病。多久做一次?

感謝,

理查德·布魯斯特 http://rabbitsoftware.com

+0

是編碼爲utf-8的有問題的文件嗎?源代碼中是否存在有問題的字符,或僅在該特定機器上編譯**之後,字符是否無效**? –

+0

這是使用靜態最終編譯成類(編譯靜態最終「烘烤」字符串到類)?或者當你說寫入磁盤時,你是序列化數據?序列化類實例?序列化方法是使用默認(即編譯平臺)編碼編譯的? –

+0

@Steve B .:事實上,所有的字符串文字和其他編譯時常量字符串都是「隱藏」到類中的,不僅是靜態的最終字符串。 –

回答

4

我大膽猜測,有編譯過程中一個轉碼問題,編譯器缺乏方向爲源文件的編碼(如見javac -encoding交換機)。

編譯器通常使用系統默認編碼,如果您不是特定的,可能導致字符串和字符文本被破壞(內部Java字節碼使用修改的UTF-8格式,因此二進制文件是可移植的)。這是我能想象到在編譯時引入問題的唯一途徑。

我已經寫了一些關於here

7

沒有像這樣的東西在內存中編碼爲ISO-8859-1的字符串。內存中的Java字符串始終是Unicode字符串。 (用UTF-16編碼,但你現在不需要這個)。

編碼只在您輸入或輸出字符串時才起作用 - 然後,在沒有明確編碼的情況下,它使用系統默認值(在某些系統上取決於用戶設置)。

正如McDowell所說,您的源文件的實際編碼應該與您的編譯器假定您的源文件的編碼相匹配,否則您在觀察時會遇到問題。您可以通過以下幾種方式實現:

  • 使用編譯器的-encoding選項,給出源文件的編碼。 (使用ant,您設置encoding=參數。)
  • 使用您的編輯器或任何其他工具(如recode)將文件的編碼更改爲編譯器默認值。
  • 使用native2ascii(使用正確的-encoding選項)將您的源文件轉換爲ASCII碼,使用\uXXXX -escapes。

在最後一種情況下,你以後可以到處與每一個默認的編碼編譯該文件,所以這可能是如果你給的源代碼,以編碼不知道的人在某處編譯的路要走。

如果你有一個更大的項目由多個文件組成,它們應該都具有相同的編碼,因爲編譯器只有一個這樣的開關,而不是幾個。

在過去幾年的所有項目中,我始終使用UTF-8對所有文件進行編碼,並在我的ant buildfile中將encoding="utf-8"參數設置爲javac任務。 (我的編輯器足夠智能,可以自動識別編碼,但我將默認設置爲UTF-8。)

編碼對其他源代碼處理工具至關重要,如javadoc。 (在那裏,你還應該爲輸出的-charset-docencoding的選擇 - 他們應該匹配,但可以對源 - -encoding不同)

+0

這不需要做源編碼。不涉及字符串文字。從網絡連接讀取字符串,然後寫入文件。 '我在內存中編碼爲ISO-8859-1'的意思是輸入流是使用該字符集讀取的,因爲這是它的編碼方式。 –

+0

「沒有給出明確的編碼,它使用系統默認的」是的,但運行時虛擬機的系統默認值,對吧?在這種情況下,編碼顯然是由編譯平臺決定的。 PrintStream的行爲有所不同,具體取決於編譯平臺。這不是可移植的行爲。你看到我的觀點了嗎? –

+0

我認爲我們需要一個最小的代碼例子。這看起來像兩個系統上的兩個編譯器選擇了不同的方法。 –

1

使用的變量名非ASCII當我遇到類似的問題(Σ ,σ,Δ,等)當做數學公式。在linux上,它在解釋時使用了UTF-8編碼。在Windows上,它抱怨無效的名稱,因爲Windows使用ISO-LATIN-1。解決方案是在我用來編譯這些文件的ant腳本中指定編碼。

+0

不錯,我想通常人們都會寫'Sigma'(或'sum'),'sigma','delta'等等,而不是使用正確的希臘字母。我曾經創建了一個名爲'ℕ'的變量。我想稱它爲'ℕ0',但是javac不接受這個,因爲'0'不是Java的數字。 –

+0

@PaŭloEbermann我遇到的問題是,有太多的變量和方程複雜到足以使文檔成爲PITA。我使用了特殊字符和文檔/正確性證明是「請參閱:skolnik,pp XXX-XXX」。變量與文本相同的事實使其他人更容易理解。 – KitsuneYMG

0

在源文件中始終使用轉義碼(例如\uxxxx),這不會成爲問題。 @Paulo提到了這一點,但我想明確地說出來。