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

輸出結果就正確了。

Image of Datadog

The Future of AI, LLMs, and Observability on Google Cloud

Datadog sat down with Google’s Director of AI to discuss the current and future states of AI, ML, and LLMs on Google Cloud. Discover 7 key insights for technical leaders, covering everything from upskilling teams to observability best practices

Learn More

Top comments (0)

A Workflow Copilot. Tailored to You.

Pieces.app image

Our desktop app, with its intelligent copilot, streamlines coding by generating snippets, extracting code from screenshots, and accelerating problem-solving.

Read the docs

👋 Kindness is contagious

Please leave a ❤️ or a friendly comment on this post if you found it helpful!

Okay