網頁

2021/1/14

Java 偵測文字檔編碼 detect charset encoding of text file

Java 偵測文字檔案字符編碼的方式如下。

Java讀取文字檔內容到程式中是逐步讀取檔案的位元組為串流輸入,然後依字符編碼(charset encoding)將讀入的位元組串流依照字符集(charset)轉成文字。從程式的角度來看讀進來的字只是一堆位元組,所以無法透過這些位元組得知文字檔的字符編碼。

如果要知道讀取文件的編碼只能透過猜測的方式。目前有相關的函式庫可利用,下面使用juniversalchardetICU4J函式庫偵測讀取的文字檔編碼。


下面讀取的hello_big5.txt內容如下,文件編碼為BIG5。

哈囉你好嗎 衷心感謝 珍重再見 期待再相逢

juniversalchardet

package com.abc.demo;

import org.mozilla.universalchardet.UniversalDetector;

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;

public class Main {

    public static void main(String[] args) {

        String encoding = detectCharSetEncoding("D:\\hello_big5.txt");
        System.out.println(encoding); // BIG5 or WINDOWS-1252

    }

    /** 使用juniversalchardet偵測文件編碼 */
    private static String detectCharSetEncoding(String filePath) {
        UniversalDetector detector = new UniversalDetector(null);
        try (
                FileInputStream fis = new FileInputStream(new File(filePath));
        ) {
            byte[] buf = new byte[1024];
            int nread;
            while ((nread = fis.read(buf)) > 0 && !detector.isDone()) {
                detector.handleData(buf, 0, nread);
            }
        } catch (IOException e) {
            e.printStackTrace();
            return "";
        }
        detector.dataEnd();
        String encoding = detector.getDetectedCharset();
        if (encoding == null) {
            return "";
        }
        return encoding;
    }

ICU4J

package com.abc.demo;

import com.ibm.icu.text.CharsetDetector;
import com.ibm.icu.text.CharsetMatch;
import org.apache.commons.io.FileUtils;

import java.io.File;
import java.io.IOException;

public class Main {

    public static void main(String[] args) {

        String encoding = detectCharSetEncoding("D:\\hello_big5.txt");
        System.out.println(encoding); // Big5 or ISO-8859-1

    }

    /** 使用ICU4J偵測文件編碼 */
    private static String detectCharSetEncoding(String filePath) {
        File file = new File(filePath);
        byte[] data = null;
        try {
            data = FileUtils.readFileToByteArray(file); // Apache Commons IO FileUtils
        } catch (IOException e) {
            e.printStackTrace();
        }

        CharsetDetector charsetDetector = new CharsetDetector();
        charsetDetector.setText(data);
        CharsetMatch charsetMatch = charsetDetector.detect();

        String encoding = charsetMatch.getName();
        if (encoding == null) {
            return "";
        }
        return encoding;
    }

}

但很多字符在不同字符集可能都有相同的編碼,這會讓猜測的結果不準確,例如上面文件內容太短可能無法測到真正的編碼是BIG5,在juniversalchardet測到WINDOWS-1252,在ICU4J測到ISO-8859-1。


沒有留言:

張貼留言