DEV Community

codemee
codemee

Posted on • Edited on

Java 讀取檔案時的編碼

JDK 18 開始, Java 預設編碼不再是使用平台的編碼, 而是 UTF-8 編碼, 以下是分別以 JDK 17 取得預設編碼的結果:

# jshell
|  Welcome to JShell -- Version 17.0.6
|  For an introduction type: /help intro

jshell> import java.nio.charset.Charset

jshell> Charset.defaultCharset()
$2 ==> x-windows-950
Enter fullscreen mode Exit fullscreen mode

如果使用 JDK 18, 結果如下:

# jshell
|  Welcome to JShell -- Version 18.0.1.1
|  For an introduction type: /help intro

jshell> import java.nio.charset.Charset

jshell> Charset.defaultCharset()
$2 ==> UTF-8
Enter fullscreen mode Exit fullscreen mode

如果你的程式在讀取檔案時都沒有指定編碼, 就要注意是否會因為編碼關係而讀取錯誤。

以指定編碼讀取檔案

如果想要讀取不同編碼的檔案, 就必須在開啟檔案時設定編碼。以下以在 JDK 18 的環境下讀取 big5 編碼的檔案為例:

我是 big-5
Enter fullscreen mode Exit fullscreen mode

要指定編碼, 可以使用 java.nio.charset.Charset 類別的 forName 方法, 傳入編碼的名稱即可:

import java.nio.charset.*;
import java.io.*;

public class RF {
  public static void main(String[] args) {
    char[] c = new char[1];
    try {
      FileReader f = new FileReader("test.txt", Charset.forName("big5"));
      while(f.read(c, 0, 1) != -1) {
        System.out.print(c[0]);
      }
    }
    catch(Exception e) {
    }
  }
}
Enter fullscreen mode Exit fullscreen mode

可用的編碼名稱可以參考 2 Supported Encodings 的列表。

對於一些國際標準的編碼, 則是在 java.nio.charset.StandarCharset 類別中已經有建好的編碼物件, 分別是 US_ASCII、ISO_8859_1、UTF_16、UTF_16BE、UTF_16LE、UTF_8, 可以直接取用。

查詢目前使用編碼

如果你擔心預設的編碼不是 UTF8, 也可以透過 Charset 的 defaultCharset() 方法查看:

jshell> import java.nio.charset.Charset

jshell> Charset.defaultCharset()
$2 ==> UTF-8
Enter fullscreen mode Exit fullscreen mode

或是也可以檢查系統變數 file.encoding

jshell> System.getProperty("file.encoding")
$3 ==> "UTF-8"
Enter fullscreen mode Exit fullscreen mode

系統變數 native.encoding 則是作業系統平台本身採用的編碼:

jshell> System.getProperty("native.encoding")
$4 ==> "MS950"
Enter fullscreen mode Exit fullscreen mode

MS950 就是 Windows 的 CP950, 也就是 Big5 編碼。

輸出時的編碼

輸出時預設會採用執行環境的編碼, JDK 18 開始可以由 System.out.charset().name() 取得, 以下是簡單的測試程式:

public class SysOutEncoding {
  public static void main(String args[]) {
    System.out.println(System.out.charset().name());
  }
}
Enter fullscreen mode Exit fullscreen mode

以下是在 Powershell 7 的實際執行結果:

# chcp
Active code page: 65001
# java .\SysOutEncoding.java
UTF-8
Enter fullscreen mode Exit fullscreen mode

如果改到 cmd 下執行:

>chcp
使用中的字碼頁: 950

>java SysOutEncoding.java
x-windows-950
Enter fullscreen mode Exit fullscreen mode

不過要注意的是, 在 jshell 中, 似乎都是採用系統預設的編碼, 像是在已經設定為 UTF-8 的 Powershell 7 中:

jshell> System.out.charset().name()
$1 ==> "x-windows-950"

jshell> System.getProperty("native.encoding")
$2 ==> "MS950"

jshell> System.out.println("測試")
����
Enter fullscreen mode Exit fullscreen mode

由於輸出編碼與 shell 不同, 所以會變成亂碼。如果想要更改 System.out 的輸出編碼, 可以這樣做:

jshell> System.setOut(new PrintStream(System.out, true, "UTF-8"))

jshell> System.out.println("測試")
測試
Enter fullscreen mode Exit fullscreen mode

輸出結果就正確了。

Top comments (0)