小師妹學JavaIO之:文件編碼和字符集Unicode

簡介

小師妹一時興起,使用了一項從來都沒用過的新技能,沒想卻出現了一個無法解決的問題。把大象裝進冰箱到底有幾步?亂碼的問題又是怎麼解決的?快來跟F師兄一起看看吧。

更多精彩內容且看:

使用Properties讀取文件

這天,小師妹心情很愉悅,吹着口哨唱着歌,標準的45度俯視讓人好不自在。

小師妹呀,什麼事情這麼高興,說出來讓師兄也沾點喜慶?

小師妹:F師兄,最新我發現了一種新型的讀取文件的方法,很好用的,就跟map一樣:

public void usePropertiesFile() throws IOException {
        Properties configProp = new Properties();
        InputStream in = this.getClass().getClassLoader().getResourceAsStream("www.flydean.com.properties");
        configProp.load(in);
        log.info(configProp.getProperty("name"));
        configProp.setProperty("name", "www.flydean.com");
        log.info(configProp.getProperty("name"));
    }

F師兄你看,我使用了Properties來讀取文件,文件裏面的內容是key=value形式的,在做配置文件使用的時候非常恰當。我是從Spring項目中的properties配置文件中得到的靈感,才發現原來java還有一個專門讀取屬性文件的類Properties。

小師妹現在都會搶答了,果然青出於藍。

亂碼初現

小師妹你做得非常好,就這樣觸類旁通,很快java就要盡歸你手了,後面的什麼scala,go,JS等估計也統統不在話下。再過幾年你就可以升任架構師,公司技術在你的帶領之下一定會蒸蒸日上。

做爲師兄,最大的責任就是給小師妹以鼓勵和信心,給她描繪美好的未來,什麼出任CEO,贏取高富帥等全都不在話下。聽說有個專業的詞彙來描述這個過程叫做:畫餅。

小師妹有點心虛:可是F師兄,我還有點小小的問題沒有解決,有點中文的小小亂碼…

我深有體會的點點頭:馬賽克是阻礙人類進步的絆腳石…哦,不是馬賽克,是文件亂碼,要想弄清楚這個問題,還要從那個字符集和文件編碼講起。

字符集和文件編碼

在很久很久以前,師兄我都還沒有出生的時候,西方世界出現了一種叫做計算機的高科技產品。

初代計算機只能做些簡單的算數運算,還要使用人工打孔的程序才能運行,不過隨着時間的推移,計算機的體積越來越小,計算能力越來越強,打孔已經不存在了,編程了人工編寫的計算機語言。

一切都在變化,唯有一件事情沒有變化。這件事件就是計算機和編程語言只流傳在西方。而西方日常交流使用26個字母加有限的標點符號就夠了。

最初的計算機存儲可以是非常昂貴的,我們用一個字節也就是8bit來存儲所有能夠用到的字符,除了最開始的1bit不用以外,總共有128中選擇,裝26個小寫+26個大寫字母和其他的一些標點符號之類的完全夠用了。

這就是最初的ASCII編碼,也叫做美國信息交換標準代碼(American Standard Code for Information Interchange)。

後面計算機傳到了全球,人們才發現好像之前的ASCII編碼不夠用了,比如中文中常用的漢字就有4千多個,怎麼辦呢?

沒關係,將ASCII編碼本地化,叫做ANSI編碼。1個字節不夠用就用2個字節嘛,路是人走出來的,編碼也是爲人來服務的。於是產生了各種如GB2312, BIG5, JIS等各自的編碼標準。這些編碼雖然與ASCII編碼但是相互之間缺並不兼容。

這嚴重的影響了國際化的進程,這樣還怎麼去實現同一個地球,同一片家園的夢想?

於是國際組織出手了,制定了UNICODE字符集,爲所有語言的所有字符都定義了一個唯一的編碼,unicode的字符集是從U+0000到U+10FFFF這麼多個編碼。

小師妹:F師兄,那麼unicode和我平時聽說的UTF-8,UTF-16,UTF-32有什麼關係呢?

我笑着問小師妹:小師妹,把大象裝進冰箱有幾步?

小師妹:F師兄,腦筋急轉彎的故事,已經不適合我了,大象裝進冰箱有三步,第一打開冰箱,第二把大象裝進去,第三關上冰箱,完事了。

小師妹呀,作爲一個有文化的中國人,要真正的承擔起民族復興,科技進步的大任,你的想法是很錯誤的,不能光想口號,要有實際的可操作性的方案才行,要不然我們什麼時候才能夠打造秦芯,唐芯和明芯呢?

師兄說的對,可是這跟unicode有什麼關係呢?

unicode字符集最後是要存儲到文件或者內存裏面的,那怎麼存呢?使用固定的1個字節,2個字節還是用邊長的字節呢?根據編碼方式的不同,可以分爲UTF-8,UTF-16,UTF-32等多種編碼方式。

其中UTF-8是一種變長的編碼方案,它使用1-6個字節來存儲。UTF-16使用2個或者4個字節來存儲,JDK9之後的String的底層編碼方式變成了兩種:LATIN1和UTF16。

而UTF-32是使用4個字節來存儲。這三種編碼方式中,只有UTF-8是兼容ASCII的,這也是爲什麼國際上UTF-8編碼方式比較通用的原因(畢竟計算機技術都是西方人搞出來的)。

解決Properties中的亂碼

小師妹,要解決你Properties中的亂碼問題很簡單,Reader基本上都有一個Charsets的參數,通過這個參數可以傳入要讀取的編碼方式,我們把UTF-8傳進去就行了:

public void usePropertiesWithUTF8() throws IOException{
        Properties configProp = new Properties();
        InputStream in = this.getClass().getClassLoader().getResourceAsStream("www.flydean.com.properties");
        InputStreamReader inputStreamReader= new InputStreamReader(in, StandardCharsets.UTF_8);
        configProp.load(inputStreamReader);
        log.info(configProp.getProperty("name"));
        configProp.setProperty("name", "www.flydean.com");
        log.info(configProp.getProperty("name"));
    }

上面的代碼中,我們使用InputStreamReader封裝了InputStream,最終解決了中文亂碼的問題。

真.終極解決辦法

小師妹又有問題了:F師兄,這樣做是因爲我們知道文件的編碼方式是UTF-8,如果不知道該怎麼辦呢?是選UTF-8,UTF-16還是UTF-32呢?

小師妹問的問題越來越刁鑽了,還好這個問題我也有準備。

接下來介紹我們的終極解決辦法,我們將各種編碼的字符最後都轉換成unicode字符集存到properties文件中,再讀取的時候是不是就沒有編碼的問題了?

轉換需要用到JDK自帶的工具:

 native2ascii -encoding utf-8 file/src/main/resources/www.flydean.com.properties.utf8 file/src/main/resources/www.flydean.com.properties.cn

上面的命令將utf-8的編碼轉成了unicode。

轉換前:

site=www.flydean.com
name=程序那些事

轉換後:

site=www.flydean.com
name=\u7a0b\u5e8f\u90a3\u4e9b\u4e8b

再運行下測試代碼:

public void usePropertiesFileWithTransfer() throws IOException {
        Properties configProp = new Properties();
        InputStream in = this.getClass().getClassLoader().getResourceAsStream("www.flydean.com.properties.cn");
        configProp.load(in);
        log.info(configProp.getProperty("name"));
        configProp.setProperty("name", "www.flydean.com");
        log.info(configProp.getProperty("name"));
    }

輸出正確的結果。

如果要做國際化支持,也是這樣做的。

總結

千辛萬苦終於解決了小師妹的問題,F師兄要休息一下。

本文的例子https://github.com/ddean2009/learn-java-io-nio

本文作者:flydean程序那些事

本文鏈接:http://www.flydean.com/io-charsets-properties/

本文來源:flydean的博客

歡迎關注我的公衆號:程序那些事,更多精彩等着您!

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章