官术网_书友最值得收藏!

2.2.4 字符編碼方式

輸入和輸出流都是用于字節序列的,但是在許多情況下,我們希望操作的是文本,即字符序列。于是,字符如何編碼成字節就成了問題。

Java針對字符使用的是Unicode標準。每個字符或“編碼點”都具有一個21位的整數。有多種不同的字符編碼方式,也就是說,將這些21位數字包裝成字節的方法有多種。

最常見的編碼方式是UTF-8,它會將每個Unicode編碼點編碼為1到4個字節的序列(請參閱表2-1)。UTF-8的好處是傳統的包含了英語中用到的所有字符的ASCII字符集中的每個字符都只會占用一個字節。

表2-1 UTF-8編碼方式

另一種常見的編碼方式是UTF-16,它會將每個Unicode編碼點編碼為1個或2個16位值(請參閱表2-2)。這是一種在Java字符串中使用的編碼方式。實際上,有兩種形式的UTF-16,被稱為“高位優先”和“低位優先”。考慮一下16位值0x2122。在高位優先格式中,高位字節會先出現:0x21后面跟著0x22。但是在低位優先格式中,是另外一種排列方式:0x22 0x21。為了表示使用的是哪一種格式,文件可以以“字節順序標記”開頭,這個標記為16位數值0xFEFF。讀入器可以使用這個值來確定字節順序,然后丟棄它。

表2-2 UTF-16編碼方式

警告:有些程序,包括Microsoft Notepad(微軟記事本)在內,都在UTF-8編碼的文件開頭處添加了一個字節順序標記。很明顯,這并不需要,因為在UTF-8中,并不存在字節順序的問題。但是Unicode標準允許這樣做,甚至認為這是一種好的做法,因為這樣做可以使編碼機制不留疑惑。遺憾的是,Java并沒有這么做,有關這個問題的缺陷報告最終是以“will not fix(不做修正)”關閉的。對你來說,最好的做法是將輸入中發現的所有先導的\uFEFF都剝離掉。

除了UTF編碼方式,還有一些編碼方式,它們各自都覆蓋了適用于特定用戶人群的字符范圍。例如,ISO 8859-1是一種單字節編碼,它包含了西歐各種語言中用到的帶有重音符號的字符,而Shift-JIS是一種用于日文字符的可變長編碼。大量的這些編碼方式至今仍在被廣泛使用。

不存在任何可靠的方式可以自動地探測出字節流中所使用的字符編碼方式。某些API方法讓我們使用“默認字符集”,即計算機的操作系統首選的字符編碼方式。這種字符編碼方式與我們的字節源中所使用的編碼方式相同嗎?字節源中的字節可能來自世界上的其他國家或地區,因此,你應該總是明確指定編碼方式。例如,在編寫網頁時,應該檢查Content-Type頭信息。

注意:平臺使用的編碼方式可以由靜態方法Charset.defaultCharset返回。靜態方法Charset.availableCharsets會返回所有可用的Charset實例,返回結果是一個從字符集的規范名稱到Charset對象的映射表。

警告:Oracle的Java實現有一個用于覆蓋平臺默認值的系統屬性file.encoding。但是它并非官方支持的屬性,并且Java庫的Oracle實現的所有部分并非都以一致的方式處理該屬性,因此,你不應該設置它。

StandardCharsets類具有類型為Charset的靜態變量,用于表示每種Java虛擬機都必須支持的字符編碼方式:

為了獲得另一種編碼方式的Charset,可以使用靜態的forName方法:

在讀入或寫出文本時,應該使用Charset對象。例如,我們可以像下面這樣將一個字節數組轉換為字符串:

提示:有些方法允許我們用一個Charset對象或字符串來指定字符編碼方式。由于選擇的是StandardCharsets常量,所以無需擔心拼寫錯誤。例如,new String(bytes,"UTF 8")就不可接受,并且會引發運行時錯誤。

警告:在不指定任何編碼方式時,有些方法(例如String(byte[])構造器)會使用默認的平臺編碼方式,而其他方法(例如Files.readAllLines)會使用UTF-8。

主站蜘蛛池模板: 富宁县| 蚌埠市| 永州市| 温州市| 水富县| 营口市| 交城县| 法库县| 宜都市| 湟中县| 卓尼县| 台东县| 华亭县| 南开区| 塔城市| 米易县| 十堰市| 柘城县| 华坪县| 化州市| 治县。| 宣威市| 北流市| 郧西县| 军事| 六盘水市| 凭祥市| 鄢陵县| 鄯善县| 章丘市| 邮箱| 延津县| 曲周县| 远安县| 金阳县| 搜索| 稻城县| 镇宁| 溧水县| 津市市| 沙湾县|