歡迎來到Linux教程網
Linux教程網
Linux教程網
Linux教程網
您现在的位置: Linux教程網 >> UnixLinux >  >> Linux編程 >> Linux編程

Java讀帶有BOM的UTF-8文件亂碼原因及解決方法

最近在處理文件時發現了同樣類型的文件使用的編碼可能是不同的。所以想將文件的格式統一一下(因為UTF-8的通用性,決定往UTF-8統一),遇見的第一個問題是:如何查看現有文件的編碼方式。

在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();
  }
 }
}

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(" ");
   }

輸出結果如下:

引用

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/

修改測試代碼中的輸入流後:

BufferedReader br = new BufferedReader(new UnicodeReader(in, Charset.defaultCharset().name()));

執行,可以看到正確的結果。

將用到的測試代碼及UTF-8讀取亂碼解決的源碼放在了附件中

免費下載地址在 http://linux.linuxidc.com/

用戶名與密碼都是www.linuxidc.com

具體下載目錄在 /2012年資料/12月/23/Java讀帶有BOM的UTF-8文件亂碼原因及解決方法

 

 

Copyright © Linux教程網 All Rights Reserved