遭遇亂碼問題的來龍去脈
這兩天寫了一個 Java 程序來玩,結果又遭遇了以前遇到過很多次的亂碼問題,具體描述一下:
在 Mac 系統里面,常用的 Java 程序啟動方式有如下幾種:
1.通過 eclipse 執行 class 入口文件啟動;
2.在 Terminal 里面用 java Test.class 或 jave -jar Test.jar 啟動
3.通過 ant 執行 class 入口文件啟動;
4.直接用 ant 執行 jar 文件;
5.用 Mac OS CoreServices 中的 Jar Launcher.app 執行 jar 文件。
6.用 Mac OS 自帶的 Jar Bundler.app 將 jar 文件包裝成 app,然后執行
執行途徑還是相當地豐富,但以不同的方式來執行,從控制台中得到的程序輸出也不一致
比如說,剛剛在 eclipse
中還能正常打印出來的漢字,在打成 jar
包以后,
雙擊該 jar
文件以 Jar Launcher.app
的方式來啟動,打印出來的文字就成了亂碼了。
畢竟寫出來的 java
程序最終還是要打成 Jar
包來使用的,總不能每次都在 eclipse
中啟動吧?
前面說過,不是第一次碰到這種問題了,於是便想着要把這個問題給解決下。
靈機一動之下想到一個好辦法,在這些啟動方式下均把 System
中的屬性遍歷打印出來,
然后用 git
來做各個版本的差異比較,有可能會套出一些蛛絲馬跡~
抱着試一試的想法實踐了一把,果然發現一些貓膩,集中體現在 file.encoding
這個屬性上面。
在 file.encoding
屬性的值是 UTF-8
時,是不存在亂碼問題的,eclipse
執行就屬於這種情況。Jar Launcher.app
執行時,該屬性的值就變成 MacRoman
了,
上面給出的資料中有對該屬性的介紹,可以用 java -D<name>=<value> Test.jar
來更改它。
另外,只有在啟動 java
程序前通過傳遞參數來更改才有效,程序一經啟動就無法再更改了。
這樣的話,也就只有通過傳遞 jvm 參數的方式來做默認編碼的變更了:
其一,寫一個帶 -Dfile.encoding=UTF-8
參數的腳本文件來啟動;
其二,用 Jar Bundler.app
打包成 app
,效率應該不如第一種方案。
原理其實都差不多,都只是將更改 jvm
默認編碼的操作封裝了起來,執行時就不用再手動鍵入了。
java 亂碼問題 -Dfile.encoding=UTF-8
-Dfile.encoding
解釋:
在命令行中輸入 java,在給出的提示中會出現 -D 的說明:-D<name>=<value>
# set a system property
-D 后面需要跟一個鍵值對,作用是設置一項系統屬性
對 -Dfile.encoding=UTF-8
來說就是設置系統屬性 file.encoding
為 UTF-8
那么 file.encoding
什么意思?字面意思為文件編碼。
搜索 java 源碼,只能找到 4 個文件中包含 file.encoding
的文件,
也就是說,只有四個文件調用了 file.encoding
這個屬性。
在 java.nio.charset
包中的 Charset.java
中,這段話的意思說的很明確了。
簡單說就是默認字符集是在 java 虛擬機啟動時決定的,
依賴於 java 虛擬機所在的操作系統的區域以及字符集。
代碼中可以看到,默認字符集就是從 file.encoding
這個屬性中獲取的。