1. 程式人生 > >【Java 程式設計】Java 字符集配置及 ObjectMapper 對映 utf8 bom 檔案時的錯誤分析

【Java 程式設計】Java 字符集配置及 ObjectMapper 對映 utf8 bom 檔案時的錯誤分析

文章目錄

1. Java 讀取檔案時的字符集配置

utf-8 文字檔案 test.txt

{
	"name": "shanghai",
	"label": "\"上海\""
}

1.1 預設字符集

比如在 Windows 平臺,開啟 CMD,可以檢視本地字符集:
在這裡插入圖片描述

public static void main( String[] args )
    {
        try ( FileReader r = new FileReader("test.txt")){
            System.out.println(r.getEncoding()); // 檢視 Java 解析文字所用的字符集
            char[] buf = new char[100];
            r.read(buf);
            System.out.print(buf);
        } catch (Exception
e){ e.printStackTrace(); } }

編譯程式,生成 demo.jar,執行:

java -jar demo.jar

打印出來的結果為 GBK! 文字解析出現亂碼,因為檔案編碼是 utf-8。

1.2 配置 Java 字符集

可以肯定的是,Java 程式並不會去識別檔案本身到底是什麼格式,而是根據配置的字符集去解析文字檔案。

預設情況下,會讀取系統本地的字符集配置,當然也可以自定義。

方法 1、 通過命令列引數配置: -Dfile.encoding

java -jar -Dfile.encoding=UTF-8 demo.jar

檔案的解析編碼為 UTF8,內容解析正確!

方法 2、通過編碼進行配置:
當通過命令列配置時,會影響整個程式解析文字的方式,有時候,想對特定檔案指定特定的解碼方式,就需要在程式碼中進行設定了!

Java 中 InputStreamReader 負責將從檔案中讀取的位元組流轉換為字元流,可以指定字符集。
在這裡插入圖片描述

程式碼如下:

String encoding = new InputStreamReader(new FileInputStream("test.txt"), "utf-8").getEncoding()
System.out.println(encoding); // utf-8

1.3 IDEA 除錯程式時的陷阱

IDEA 除錯程式時,會新增很多引數,包括字符集配置。

可以通過 Jconsole 檢視 IDEA 啟動的 Java 程式的 VM 引數,如下:
在這裡插入圖片描述

因此,在讀取外部檔案時,如果該檔案是 utf-8 格式,那麼通過 IDEA 除錯時,讀取並解析檔案是沒有問題的,但當通過 java 命令執行程式時,如果沒有指定 -Dfile.encoding 引數,且本地字符集配置的是 GBK,就會出現錯誤(亂碼),而這種錯誤顯得很詭異,因為在測試環境上有問題,本地除錯卻無法復現!!!!

2. utf-8 與 utf-8 No Bom

首先,UTF-8 不需要 BOM,儘管 Unicode 標準允許在 UTF-8 中使用 BOM。不含 BOM 的 UTF-8 才是標準形式,在 UTF-8 檔案中放置 BOM 主要是微軟的習慣。

在 Windows 平臺,用記事本開啟並儲存的檔案,預設就是 utf-8 bom 檔案,bom 檔案會在檔案頭上新增 EF BB BF 位元組流。

使用 ultra edit 檢視 test.txt 的十六進位制內容:
utf-8 no bom
在這裡插入圖片描述

utf-8 bom
在這裡插入圖片描述

使用 ultra edit 可以將檔案另存為期望的格式:
在這裡插入圖片描述

此外, IntellJ IDEA 建立和儲存的文字檔案是 no bom 的,畢竟 Java 是平臺無關的!!!

3. ObjectMapper 與 bom

程式語言一般都是平臺無關的,因此 bom 檔案常常會誘發一些錯誤!

Java 本身就是平臺無關的,所以當 Java 在讀取 utf-8 bom 檔案時並不會自動忽略掉 Windows 為檔案新增的 EF BB BF 檔案頭,而是將 EF BB BF 視作檔案內容。

因此當使用 ObjectMapper 將檔案中的 json 字串轉換為 Object 時,utf-8 bom 檔案會報錯!

com.fasterxml.jackson.core.JsonParseException: Unexpected character ('' (code 65279 / 0xfeff)): expected a valid value (number, String, array, object, 'true', 'false' or 'null')

這時,需要將檔案轉存為 no bom 格式!

測試程式碼

import com.fasterxml.jackson.databind.ObjectMapper;
import java.io.FileReader;

public class Demo
{	
	public static class Data {
        String name;
        String label;

        public String getName() {
            return name;
        }

        public void setName(String name) {
            this.name = name;
        }

        public String getLabel() {
            return label;
        }

        public void setLabel(String label) {
            this.label = label;
        }

        @Override
        public String toString() {
            return "Data{" +
                    "name='" + name + '\'' +
                    ", label='" + label + '\'' +
                    '}';
        }
    }

	public static void main(String[] args)
	{
		try ( FileReader r1 = new FileReader("test.txt");
			  FileReader r2 = new FileReader("test.txt")){

            Data d = new ObjectMapper().readValue(r1, Data.class);
            System.out.println(d);

            System.out.println(r2.getEncoding());
            char[] buf = new char[100];
            r2.read(buf);
            System.out.print(buf);
        } catch (Exception e){
            e.printStackTrace();
        }
}