程式扎記: [ Java 代碼範本 ] 判斷檔案編碼 - java.nio.charset.CharsetDecoder

標籤

2012年10月15日 星期一

[ Java 代碼範本 ] 判斷檔案編碼 - java.nio.charset.CharsetDecoder

來源自 這裡 
功能說明: 
當你拿到一個文字檔, 除了透過文字編輯器告訴你是什麼編碼, 有沒有辦法透過代碼告訴你該文字檔的編碼? 可以試試 java.nio.charset.CharsetDecoder
底下的代碼使用該類別對文字檔的內容進行 decoding, 如果可以成功使用某種編碼完整的 decoding 該文字檔, 便猜測該文字檔使用該種編碼: 
  1. public Charset detectCharset(File f, String[] charsets) {  
  2.   
  3.        Charset charset = null;  
  4.   
  5.        // charsets 是我們定義的 編碼 矩陣, 包括 UTF8, BIG5 etc.  
  6.        for (String charsetName : charsets) {  
  7.            charset = detectCharset(f, Charset.forName(charsetName));  
  8.            if (charset != null) {  
  9.                break;  
  10.            }  
  11.        }  
  12.        System.out.printf("\t[Test] Using '%s' encoding!\n", charset);  
  13.        return charset;  
  14.    }  
  15.   
  16.    private Charset detectCharset(File f, Charset charset) {  
  17.        try {  
  18.            BufferedInputStream input = new BufferedInputStream(new FileInputStream(f));  
  19.   
  20.            CharsetDecoder decoder = charset.newDecoder();  
  21.            decoder.reset();  
  22.   
  23.            byte[] buffer = new byte[512];  
  24.            boolean identified = false;  
  25.            while ((input.read(buffer) != -1) && (!identified)) {  
  26.                identified = identify(buffer, decoder);  
  27.            }  
  28.   
  29.            input.close();  
  30.   
  31.            if (identified) {  
  32.                return charset;  
  33.            } else {  
  34.                return null;  
  35.            }  
  36.   
  37.        } catch (Exception e) {  
  38.            return null;  
  39.        }  
  40.    }  
範例代碼: 
底下代碼對文字檔 "example.txt" 或 "example_utf8.txt" 進行編碼的偵測: 
  1. package test;  
  2.   
  3. import java.io.BufferedInputStream;  
  4. import java.io.File;  
  5. import java.io.FileInputStream;  
  6. import java.io.FileNotFoundException;  
  7. import java.io.IOException;  
  8. import java.io.InputStreamReader;  
  9. import java.nio.ByteBuffer;  
  10. import java.nio.charset.CharacterCodingException;  
  11. import java.nio.charset.Charset;  
  12. import java.nio.charset.CharsetDecoder;  
  13.   
  14. public class CharsetDetector {  
  15.     public Charset detectCharset(File f, String[] charsets) {  
  16.   
  17.         Charset charset = null;  
  18.   
  19.         // charsets 是我們定義的 編碼 矩陣, 包括 UTF8, BIG5 etc.  
  20.         for (String charsetName : charsets) {  
  21.             charset = detectCharset(f, Charset.forName(charsetName));  
  22.             if (charset != null) {  
  23.                 break;  
  24.             }  
  25.         }  
  26.         System.out.printf("\t[Test] Using '%s' encoding!\n", charset);  
  27.         return charset;  
  28.     }  
  29.   
  30.     private Charset detectCharset(File f, Charset charset) {  
  31.         try {  
  32.             BufferedInputStream input = new BufferedInputStream(new FileInputStream(f));  
  33.   
  34.             CharsetDecoder decoder = charset.newDecoder();  
  35.             decoder.reset();  
  36.   
  37.             byte[] buffer = new byte[512];  
  38.             boolean identified = false;  
  39.             while ((input.read(buffer) != -1) && (!identified)) {  
  40.                 identified = identify(buffer, decoder);  
  41.             }  
  42.   
  43.             input.close();  
  44.   
  45.             if (identified) {  
  46.                 return charset;  
  47.             } else {  
  48.                 return null;  
  49.             }  
  50.   
  51.         } catch (Exception e) {  
  52.             return null;  
  53.         }  
  54.     }  
  55.   
  56.     private boolean identify(byte[] bytes, CharsetDecoder decoder) {  
  57.         try {  
  58.             decoder.decode(ByteBuffer.wrap(bytes));  
  59.         } catch (CharacterCodingException e) {  
  60.             return false;  
  61.         }  
  62.         return true;  
  63.     }  
  64.   
  65.     public static void main(String[] args) {  
  66.         File f = new File("example.txt");  
  67.   
  68.         String[] charsetsToBeTested = {"UTF-8""big5""windows-1253""ISO-8859-7"};  
  69.   
  70.         CharsetDetector cd = new CharsetDetector();  
  71.         Charset charset = cd.detectCharset(f, charsetsToBeTested);  
  72.   
  73.         if (charset != null) {  
  74.             try {  
  75.                 InputStreamReader reader = new InputStreamReader(new FileInputStream(f), charset);  
  76.                 int c = 0;  
  77.                 while ((c = reader.read()) != -1) {  
  78.                     System.out.print((char)c);  
  79.                 }  
  80.                 reader.close();  
  81.             } catch (FileNotFoundException fnfe) {  
  82.                 fnfe.printStackTrace();  
  83.             }catch(IOException ioe){  
  84.                 ioe.printStackTrace();  
  85.             }  
  86.   
  87.         }else{  
  88.             System.out.println("Unrecognized charset.");  
  89.         }  
  90.     }  
  91. }  
如果使用文字檔 example.txt (big5 編碼), 可以得到輸出: 
[Test] Using 'Big5' encoding!
這是中文

如果是文字檔 example_utf8.txt (utf8 編碼), 可以得到輸出: 
[Test] Using 'UTF-8' encoding!
這是中文

補充說明: 
該代碼是使用 try-and-error 進行猜測, 但是有可能多種編碼可以同時對某個文件進行 decoding (不對的編碼會出現亂碼), 因此在安排 "編碼矩陣時" 應該把常出現的編碼擺在前面, 以避免使用 "不恰當的編碼" 卻能夠正常 decoding 文字檔造成的亂碼. 

[ Java常見問題 ] Java讀帶有BOM的UTF-8文件亂碼原因及解決方法 
[ Java 常見問題 ] Handle UTF8 file with BOM

沒有留言:

張貼留言

網誌存檔

關於我自己

我的相片
Where there is a will, there is a way!