Linux 系統預設編碼為 UTF-8,但 Java 在讀取檔案系統中文檔名時,若編碼轉換處理不當,常出現 `?????` 或亂碼。本文分析根因並提供正確解決方案。
File[] files = dir.listFiles();
for (File f : files) {
String name = f.getName(); // 直接取得可能已是亂碼
// 錯誤嘗試:new String(name.getBytes("GB2312"), "UTF-8"); // 雙重轉碼導致更糟
}
java -Dfile.encoding=GBK -jar your-app.jar
或在程式碼啟動早期(如 `main` 第一行)強制設定(不保證所有 JVM 有效):
System.setProperty("file.encoding", "GBK");
Path dir = Paths.get("/path/to/dir");
try (DirectoryStream stream = Files.newDirectoryStream(dir)) {
for (Path entry : stream) {
// 取得檔名位元組並以正確編碼解碼
byte[] nameBytes = entry.getFileName().toString().getBytes(StandardCharsets.ISO_8859_1); // 先以 ISO-8859-1 還原原始位元組
String correctName = new String(nameBytes, "GBK"); // 再以實際編碼解碼
System.out.println(correctName);
}
}
原理:`Path.getFileName()` 回傳的字串若以 ISO-8859-1(單位元組對應)轉回位元組,可還原檔案系統原始位元組序列,再以正確編碼(GBK/Big5)解碼。
「用 `new String(name.getBytes("UTF-8"), "UTF-8")` 就能修好」
錯誤。若 JVM 已以 UTF-8 錯誤解碼 GBK 位元組,產生的 `String` 內含替換字元 `` (U+FFFD),再轉回 UTF-8 位元組仍是替換字元位元組,無法還原原始中文。