在前面的字符集編碼系列中,已經探討了幾大主要的字符集編碼。在此基礎之上,這裏將進一步探討編碼的應用及亂碼的根源,咱們先從基本的文件提及。html
文件(內容)就是字節序列。文本文件也是文件,因此它也是字節序列。java
一般說到文件時,指的是文件內容,但文件還有文件名,文件名與文件內容是分開存儲的。windows
你能夠在硬盤上新建一個文件,它的大小爲0.以下:api
但它是有文件名的,好比上述的「新建文本文檔.txt「,保存這些名字天然也要佔用空間,只不過它與文件內容是分離的。架構
這些由操做系統的文件系統模塊負責。oracle
文件名是一段文本,所以它會涉及字符集編碼。測試
文件內容則視狀況而定:編碼
1. 文本文件,確定會涉及字符集編碼。spa
常見的好比txt,html,xml以及各類源代碼文件等等。操作系統
2. 非文本文件,好比圖片文件jpg,gif之類,天然跟字符集編碼無關了。
有些文件,好比Word的doc之類的,混合了圖片跟文本在裏面,能夠想像,其中的文本部分天然也會牽涉到字符集編碼的問題,只不過這些編碼不禁咱們去控制,咱們一般也無須去關心。
文件名是一串文本,所以它必然涉及某種字符集編碼,只不過這種編碼是由操做系統決定的,咱們無權干預。
那麼,它用的是什麼編碼呢?在Windows下,能夠簡單作些實驗。咱們能夠弄些奇怪的文件名如「★★★★.txt」,以下:
結果也能保存。這些字符只在Unicode中才有,因此它確定不是用的GBK之類的。
Windows下NTFS架構文件名使用UTF-16編碼。但對於FAT之類的,則是所謂的「OEM character set」。
MSDN上的原文以下:「NTFS stores file names in Unicode. In contrast, the older FAT12, FAT16, and FAT32 file systems use the OEM character set」(NTFS使用Unicode存儲文件名。與此相對,老的FAT12,FAT16和FAT32文件系統使用OEM字符集).參見http://msdn.microsoft.com/en-us/library/windows/desktop/dd317748%28v=vs.85%29.aspx
注:在Windows語境中,UTF-16一般叫成Unicode。
結合實驗的結果,能夠肯定,Windows使用UTF-16對文件名進行編碼。(個人系統是Win 7,文件系統爲NTFS)
不過,不一樣的系統平臺可能使用了不一樣的編碼。好比最新的Linux平臺對文件名採用了UTF-8編碼,但早期的則很差說,甚至沒有一個標準。
若是你不是Windows平臺,你也能夠簡單作些實驗來大體猜想一下文件系統使用的編碼。
因爲對文件名沒有一個統一的編碼,不一樣系統平臺間交換文件時,中文文件名極易發生亂碼現象。好比FTP上傳,網頁文件上傳及下載等狀況下常常能遇到文件名亂碼。
不過,須要注意的是,交換過程當中,文件內容不會發生任何改變。即使是文本文件,也徹底是字節傳送,不會涉及任何的編解碼。
你可能碰到過這樣的事,把一個文本文件從Windows平臺上傳到Linux平臺,並在Linux平臺下打開時發現亂碼了,但這不意味着文件內容有了什麼變化,一般的緣由是你的文件是用GBK編碼的,但Linux平臺下打開時它缺省可能用的是UTF-8編碼去讀取,所以,你只要調整成正確的編碼去讀取便可。
在這裏,咱們討論了文件名的編碼,以後,如無特別說明,談到編碼時均指對文件內容的編碼。一般,這是咱們更爲關心的內容。
一般,說到字符集編碼都是對文本文件而言的,但非文本文件也是可能用到字符集編碼的。
好比,Word用什麼編碼?word生成的doc或者docx雖然不是文本文件,但咱們能夠想像,它裏面可能有圖像,又有文字。其中的文字天然也會用到某種編碼。只不過,這些都不須要咱們去操心。
下面是一個實驗,新建一個空白的doc文檔,錄入幾個簡單字符」Hello你好」
保存成doc文件,再用notepad++打開,以十六進制形式查看:
如上圖,搜索到hello幾個關鍵字,咱們知道,「H」的碼點是U+0048,而「你」的碼點則是U+4F60,因此,很顯然,用的是UTF-16 LE(Little Endian,小端序)
關於端序及BOM的相關話題,可參見字符集與編碼(七)——BOM
注:這只是我我的在本機測試的結果,不表明廣泛的結論,不一樣平臺不一樣版本下的可能會有差別,誰知道呢?我沒有去研究過doc文件格式的規範,這個doc我仍是用WPS生成的!
又好比,Java中的class文件,它也不是文本文件,一般稱爲字節碼文件。但它裏面也會保存String的常量,這天然又要牽涉到編碼。實際用的是所謂的「modified UTF-8」編碼。
簡單創建一個java文件,定義一個string常量」Hello你好「:
public class Foo { static final String HI = "Hello你好"; }
保存並用javac命令編譯獲得class文件,再次用notepad++打開並以十六進制形式查看:
搜索到Hello幾個關鍵字,緊接在它們後面的」e4 bd a0「就是」你「的UTF-8編碼了。
在前面的字符集與編碼(四)——Unicode中,曾提到過,漢字的UTF-8編碼一般都是以e打頭,形如ex xx xx這樣,這是經常使用漢字UTF-8編碼的一個重要特徵。
這個」modified UTF-8」編碼與UTF-8相似,但有一些差異,它的名字也暗示了這一點。
好比對於U+0000它用了兩字節來編碼;
還有對U+FFFF以上的字符它採用了6字節編碼而非正常UTF-8的四字節編碼,實質是對代理對(surrogate pairs)的值進行編碼。
詳情可參見http://docs.oracle.com/javase/7/docs/api/java/io/DataInput.html#modified-utf-8
文本文件也是文件,因此它也是字節序列。當讀取一個文本文件時,最重要的是肯定它所使用的編碼,只有這樣才能正確的解碼。
因爲牽涉的狀況較多,咱們將在下一篇討論這一問題。