天天看點

該死的BOM(byte-order mark)

該死的BOM(byte-order mark)

2011-11-02 建立

    最近接連遇到兩個奇怪的事情,一,在WINDOWS CYGWIN下可以編譯的C++代碼檔案,到了LINUX環境下使用GCC報存在遊離的字元,導緻編譯失敗。

    (gcc編譯報錯:程式中有遊離的‘\357’‘\273’‘\277’等 ,其原因有可能是

           1,誤用了全角的符号和空格等,

           2,BOM字元。)

    二,在WINDOWS下正常解析的XML檔案在LINUX裝置上報“前導字元錯誤”。

   最後發現這些問題都是微軟的BOM字元惹的禍。

什麼是BOM

    BOM(byte-order mark),即位元組順序标記,它是插入到以UTF-8、UTF16或UTF-32編碼Unicode檔案開頭的特殊标記,用來識别Unicode檔案的編碼類型。具體編碼如下表:

BOM                  Encoding 

EF BB BF         UTF-8

FE FF                UTF-16 (big-endian)

FF FE                UTF-16 (little-endian)

00 00 FE FF     UTF-32 (big-endian)

FF FE 00 00     UTF-32 (little-endian)

   微軟建議所有的 Unicode 檔案應該以 ZERO WIDTH NOBREAK SPACE(U+FEFF)字元開頭。這作為一個“特征符”來識别檔案中使用的編碼和位元組順序。BOM的本意不錯,但它并不是一個通用标準,進而導緻了很多不相容的問題。

1. JDK1.5以及之前的Reader都不能處理帶有BOM的UTF-8編碼的檔案,解析這種格式的xml檔案時,會抛出異常:Content is not allowed in prolog.

2. Linux/UNIX 并沒有使用 BOM,因為它會破壞現有的 ASCII 檔案的文法約定。

3, 目前GCC編譯器不接受帶有BOM的源代碼檔案

   不同的編輯工具對BOM的處理也各不相同。使用Windows自帶的記事本将檔案儲存為UTF-8編碼的時候,記事本會自動在檔案開頭插入BOM(雖然BOM對UTF-8來說并不是必須的),但是其它編輯器的就不會這樣做,或者有專門的選項決定其行為。

   當然解決BOM相容性這個問題也簡單,使用工具将帶有BOM的檔案儲存成不帶BOM的檔案,(例如可以使用Visual Studio進行轉換,選擇“檔案/進階儲存選項”,選擇儲存為 Unicode(UTF-8 無簽名) - 代碼頁65001 即可),或者自己使用工具删除前導字元就可以了。如果是在程式中處理,可以以二進制方式打開檔案,判斷一下是否存在BOM字元,然後再進行删除或忽略BOM字元的操作。

   最後,如果這時你的文檔為帶BOM的UTF-8檔案,使用的二進制編輯工具又恰好是ULTRAEDIT,很可能會碰到另外的奇怪的問題,将該檔案二進制顯示,會發現前導位元組為FFFE,以及文檔中的英文字元是兩個位元組,而不是UTF-8中的一個位元組,自己編寫一個小的二進制讀取工具會發現文檔并沒有問題,前導位元組是EFBBBF,英文字元也是一個位元組的。原因是預設配置的ULTRAEDIT對UTF-8進行了自動的轉換,轉為UNICODE LE格式,如果關閉其“自動檢測UTF-8格式資料”的選項,可以發現二進制顯示沒有問題,但文本顯示中的前導位元組和中文等字元會變成亂碼。是以該選項決定了ULTRAEDIT能夠正确顯示UTF-8檔案的文本格式還是二進制格式,一般我們還是選擇正确的文本顯示,因為大部分情況下需要的是文本編輯。但如果使用ULTRAEDIT删除前導的BOM,需要暫時關閉該選項後再進行二進制編輯。

自動轉換為UNICODE LE的UTF8編碼XML檔案二進制顯示

該死的BOM(byte-order mark)

不自動轉換的帶有BOM的UTF8編碼XML檔案二進制顯示

該死的BOM(byte-order mark)

不自動轉換的不帶有BOM的UTF8編碼XML檔案二進制顯示

該死的BOM(byte-order mark)

繼續閱讀