Java讀取UTF-8的txt文件第一行出現亂碼“?”及解決
test.txt文件內容:
A中
2國
3
4
5
6
test.txt文件采用寫字板保存為UTF-8格式
保存並關閉后使用寫字板再次打開該UTF-8文檔,中文、字母正常顯示
測試代碼:
- import java.io.BufferedReader;
- import java.io.File;
- import java.io.FileInputStream;
- import java.io.InputStreamReader;
- public class ReadTxtFile {
- public static void main(String[] args) {
- try {
- String charsetName = "UTF-8";
- String path = "D:/to_delete/test.txt";
- File file = new File(path);
- if (file.isFile() && file.exists())
- {
- InputStreamReader insReader = new InputStreamReader(
- new FileInputStream(file), charsetName);
- BufferedReader bufReader = new BufferedReader(insReader);
- String line = new String();
- while ((line = bufReader.readLine()) != null) {
- System.out.println(line);
- }
- bufReader.close();
- insReader.close();
- }
- } catch (Exception e) {
- System.out.println("讀取文件內容操作出錯");
- e.printStackTrace();
- }
- }
- }
程序執行結果:
?A中
2國
3
4
5
6
我的解決辦法:
使用UltraEdit將上邊的txt文件另存為UTF-8無BOM格式;
或者
使用Notepad++打開上邊的txt文件執行如下操作“格式-->以UTF-8無BOM格式編碼”,修改后將txt文本進行保存。
網上有篇非常好的文章,論述了問題出現的原因及解決辦法
Java讀帶有BOM的UTF-8文件亂碼原因及解決方法
url:http://daimojingdeyu.javaeye.com/blog/397661
關鍵字: java 讀utf-8, java寫utf-8, 編碼, utf-8 亂碼
最近在處理文件時發現了同樣類型的文件使用的編碼可能是不同的。所以想將文件的格式統一一下(因為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格式保存,則在使用程序讀取是會從文件中多讀出一個不可見字符。
測試代碼如下:
utf.txt通過記事本創建,另存時使用指定utf-8編碼,其內容為:
This is the first line.
This is second line.
正常的測試結果應該是直接輸出utf.txt的文本內容。可是實際上卻輸出了下面的內容:
?This is the first line.
This is second line.
第一行多出了一個問號。
通過上面的幾篇文章應該可以想到是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循環中可加入下面的代碼,測試一下讀出內容:
輸出結果如下:
EF BB BF 54 68 69 73 20 69 73 20 74 68 65 20 66 69 72 73 74 20 6C 69 6E 65 2E
?This is the first line.
54 68 69 73 20 69 73 20 73 65 63 6F 6E 64 20 6C 69 6E 65 2E
This is second line.
紅色部分的"EF BB BF"剛好是UTF-8文件的BOM編碼,可以看出Java在讀文件時沒能正確處理UTF-8文件的BOM編碼,將前3個字節當作文本內容來處理了。
使用鏈接中提供的代碼可以解決碰到的亂碼問題:
http://koti.mbnet.fi/akini/java/unicodereader/
上網找了一下,找到幾篇比較好文章,這里就不轉載啦把鏈接搞過來。
文件編碼問題集錦
字符串編碼(charset,encoding,decoding)問題原理
Java編碼淺析
判定文件編碼或文本流編碼的方法
上面的幾篇文章可以看成認識編碼問題的“從入門到精通”
如果你看完了上面的文章,一定了解到了,在java中,class文件采用utf8的編碼方式,JVM運行時采用utf16。Java的字符串是永遠都是unicode的,采用的是UTF-16的編碼方式。
想測試一下,java對UTF-8文件的讀寫的能力,結果發現了一個很郁悶的問題,如果通過java寫的UTF-8文件,使用Java可以正確的讀,但是如果用記事本將相同的內容使用UTF-8格式保存,則在使用程序讀取是會從文件中多讀出一個不可見字符。
測試代碼如下:
- 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();
- }
- }
- }
- 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編碼,其內容為:
引用
This is the first line.
This is second line.
正常的測試結果應該是直接輸出utf.txt的文本內容。可是實際上卻輸出了下面的內容:
引用
?This is the first line.
This is second line.
第一行多出了一個問號。
通過上面的幾篇文章應該可以想到是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(" ");
- }
- 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 54 68 69 73 20 69 73 20 74 68 65 20 66 69 72 73 74 20 6C 69 6E 65 2E
?This is the first line.
54 68 69 73 20 69 73 20 73 65 63 6F 6E 64 20 6C 69 6E 65 2E
This is second line.
紅色部分的"EF BB BF"剛好是UTF-8文件的BOM編碼,可以看出Java在讀文件時沒能正確處理UTF-8文件的BOM編碼,將前3個字節當作文本內容來處理了。
使用鏈接中提供的代碼可以解決碰到的亂碼問題:
http://koti.mbnet.fi/akini/java/unicodereader/