哪來的純文字檔?


也許在 Windows 中,你用滑鼠點兩下 .txt 檔案,就會使用「記事本」之類的程式開啟「純文字檔案」,顯示其中的一些文字,你鍵入幾個文字後存檔,下次再開啟檔案,仍可以看到原本輸入的文字。

有些檔案,如果你硬是用「記事本」之類的「純文字編輯器」開啟,例如 .exe,那麼會看到一堆「亂碼」,通常稱這種檔案叫「二進位檔案」。

其實所有的檔案,都是用二進位方式儲存,並沒有純文字檔案或二進位檔案的區別,即使是所謂純文字檔案,也是用二進位方式儲存,例如在檔案中輸入 Justin,若用可以檢視二進位或 16 進位的編輯器來觀看,會看到:

哪來的純文字檔?

J、u、s、t、i、n 五個字元分別儲存為二進位的位元組(Byte)值,以 16 進位值來顯示就是 4A、75、73、74、69、6E,如果對照 ASCII 表格,4A、75、73、74、69、6E 就是編碼表中的 J、u、s、t、i、n 字元。

所謂純文字文件,不過是編輯器讀取檔案的二進位資料,嘗試對照某個編碼之後,再繪製出對應的字元外觀,那麼,若新增一個所謂「純文字檔案」,那編輯器會預設用哪個編碼來儲存檔案呢?例如方才的 J 這個字元,編輯器為什麼儲存為 4A(1001010)呢?

通常系統內建的編輯器會使用作業系統預設編碼,舉例來說,在正體中文 Windows 中預設的編碼為 MS950,其中英文字元的編碼相容於 ASCII,所以鍵入英文字元 J,才會儲存為 4A 的位元組,那如果鍵入中文字元呢?例如輸入「測試」,用 16 進位方式來檢視就會是:

哪來的純文字檔?

MS950 編碼中,中文字是用兩個位元組來儲存,MS950 可視為 Big5 的擴充,如果查 Big5 編碼表,會發現 B4FA 就是「測」字的編碼, B8D5 就是「試」字的編碼。

那麼在正體中文 Windows 中,若文字檔案中同時存在著英文字與中文字,那文字編輯器如何知道哪些位元組是英文字的資料,哪兩個位元組要合在一起顯示中文字元呢?

Big5 為例,為了與 ASCII 相容,採第一個位元組範圍為 0xA4 至 0xF9,而第二個位元組為 0x40 到 0x7E 以及 0xA1 至 0xFE,兩個位元組來組成一個中文字,讀取時若要先讀到位元組是在 0xA4 至 0xF9,就表示它可能是一個中文字的前半,此時再讀入下一個位元組,然後再依編碼表繪製出中文字,如果先讀到的位元組是在 0xA3 以內,直接用該位元組繪製出文字。下面這個簡單的程式,依以上所述規則,對 Big5 中文字與非中文字作簡單的判斷:

package cc.openhome;

import java.nio.file.Files;
import java.nio.file.Paths;
import static java.lang.System.out;

public class Main {    
    public static void main(String[] args) throws Exception {
        byte[] bytes = Files.readAllBytes(Paths.get("sample.txt"));

        int i = 0;
        while(i < bytes.length) {
            if(notBig5(toInt(bytes[i]))) {
                byte[] other = {0, bytes[i]};
                i++;
                print(other);
            } else {
                byte[] big5 = {bytes[i], bytes[i + 1]};
                i += 2;
                print(big5);
            }
        }
    }

    private static int toInt(byte b) {
        return b & 0x00FF;
    }

    private static boolean notBig5(int dec) {
        return dec < 0xA4 || dec >= 0xF9;
    }

    private static void print(byte[] bytes) {
        out.printf("%-3h", toInt(bytes[0]));
        out.printf("%-3h", toInt(bytes[1]));
        out.printf("%s%n", new String(bytes));
    }
}

如果在正體中文 Windows 下開一個純文字檔案sample.txt,用預設編碼儲存「這T是e個s測t試」的文字,使用十六進位編輯器檢祝會有以下的結果:

哪來的純文字檔?

使用以上程式會顯示如下結果:

C:\workspace>java cc.openhome.Main sample.txt

b3 6f 這
0  54  T
ac 4f 是
0  65  e
ad d3 個
0  73  s
b4 fa 測
0  74  t
b8 d5 試

可以分別對照看看,圖片與執行結果中的十六進位號碼是相符的。