最近在處理文件時發現了一樣類型的文件使用的編碼多是不一樣的。因此想將文件的格式統一一下(由於UTF-8的通用性,決定往UTF-8統一),碰見的第一個問題是:如何查看現有文件的編碼方式。
上網找了一下,找到幾篇比較好文章,這裏就不轉載啦把連接搞過來。
文件編碼問題集錦
字符串編碼(charset,encoding,decoding)問題原理
Java編碼淺析
斷定文件編碼或文本流編碼的方法
上面的幾篇文章能夠當作認識編碼問題的「從入門到精通」
若是你看完了上面的文章,必定了解到了,在java中,class文件採用utf8的編碼方式,JVM運行時採用utf16。Java的字符串是永遠都是unicode的,採用的是UTF-16的編碼方式。
想測試一下,java對UTF-8文件的讀寫的能力,結果發現了一個很鬱悶的問題,若是經過java寫的UTF-8文件,使用Java能夠正確的讀,可是若是用記事本將相同的內容使用UTF-8格式保存,則在使用程序讀取是會從文件中多讀出一個不可見字符。
測試代碼以下: java
import java.io.BufferedReader; import java.io.File; import java.io.FileInputStream; import java.io.IOException; import java.io.InputStreamReader; public class UTF8Test { public static void main(String[] args) throws IOException { File f = new File("./utf.txt"); FileInputStream in = new FileInputStream(f); // 指定讀取文件時以UTF-8的格式讀取 BufferedReader br = new BufferedReader(new InputStreamReader(in, "UTF-8")); String line = br.readLine(); while(line != null) { System.out.println(line); line = br.readLine(); } } }utf.txt經過記事本建立,另存時使用指定utf-8編碼,其內容爲:
正常的測試結果應該是直接輸出utf.txt的文本內容。但是實際上卻輸出了下面的內容: 測試
第一行多出了一個問號。
經過上面的幾篇文章應該能夠想到是Java讀取BOM(Byte Order Mark)的問題,在使用UTF-8時,能夠在文件的開始使用3個字節的"EF BB BF"來標識文件使用了UTF-8的編碼,固然也能夠不用這個3個字節。
上面的問題應該就是由於對開頭3個字節的讀取致使的。開始不太相信這個是JDK的Bug,後來在屢次試驗後,問題依然存在,就又狗狗了一下,果真找到一個以下的Bug:
Bug ID:4508058
不過在我關掉的一些頁面中記得有篇文件說這個bug只在jdk1.5及以前的版本纔有,說是1.6已經解決了,從目前來看1.6只是解決了讀取帶有BOM文件失敗的問題,仍是不能區別處理有BOM和無BOM的UTF-8編碼的文件,從Bug ID:4508058裏的描述能夠看出,這個問題將做爲一個不會修改的問題關閉,對於BOM編碼的識別將由應用程序本身來處理,緣由可從另處一個bug處查看到,由於Unicode對於BOM的編碼的規定可能發生變化。也就是說對於一個UTF-8的文件,應用程序須要知道這個文件有沒有寫BOM,而後本身決定處理BOM的方式。
在上面的while循環中可加入下面的代碼,測試一下讀出內容: 編碼
byte[] allbytes = line.getBytes("UTF-8"); for (int i=0; i < allbytes.length; i++) { int tmp = allbytes[i]; String hexString = Integer.toHexString(tmp); // 1個byte變成16進制的,只須要2位就能夠表示了,取後面兩位,去掉前面的符號填充 hexString = hexString.substring(hexString.length() -2); System.out.print(hexString.toUpperCase()); System.out.print(" "); }輸出結果以下:
紅色部分的"EF BB BF"恰好是UTF-8文件的BOM編碼,能夠看出Java在讀文件時沒能正確處理UTF-8文件的BOM編碼,將前3個字節看成文本內容來處理了。
使用連接中提供的代碼能夠解決碰到的亂碼問題:
http://koti.mbnet.fi/akini/java/unicodereader/
修改測試代碼中的輸入流後: spa
BufferedReader br = new BufferedReader(new UnicodeReader(in, Charset.defaultCharset().name()));
執行,能夠看到正確的結果。
將用到的測試代碼及UTF-8讀取亂碼解決(http://koti.mbnet.fi/akini/java/unicodereader)的源碼放在了附件中 .net