Linux 預設編碼為 UTF-8,檔案系統儲存中文檔名無問題。但 Java 程式用 File.listFiles() 讀取時,中文檔名顯示為 ????? 或亂碼。嘗試 new String(name.getBytes("GB2312"), "UTF-8") 反而全變 ?????。
char),String.getBytes(charset) 是「按指定編碼**編碼**為位元組」,new String(bytes, charset) 是「按指定編碼**解碼**為字串」。file.encoding)非 UTF-8(如 ISO-8859-1),則 File.getName() 回傳的字串已經在錯誤編碼下解碼完成,**資訊已遺失**,後續轉碼無法挽回。java -Dfile.encoding=UTF-8 -Dsun.jnu.encoding=UTF-8 -jar your-app.jar
file.encoding:影響 new String(bytes)、String.getBytes() 預設編碼。sun.jnu.encoding:影響 File、FileInputStream 等檔案系統 API 的編碼(JDK 內部屬性)。亦可在程式碼最早處呼叫 System.setProperty("file.encoding", "UTF-8"),**但必須在任何檔案操作前**,且不保證所有 JDK 版本生效,啟動參數最穩妥。
# /etc/locale.gen 取消註解 en_US.UTF-8 UTF-8
locale-gen
export LANG=en_US.UTF-8
export LC_ALL=en_US.UTF-8
確保 locale 輸出皆為 UTF-8,JVM 啟動會自動採用。
// 讀取目錄
File dir = new File("/path");
File[] files = dir.listFiles();
for (File f : files) {
// 若確定檔案系統為 UTF-8,直接用
String name = f.getName(); // 已正確解碼
// 若需轉為 bytes 再處理
byte[] utf8Bytes = name.getBytes(StandardCharsets.UTF_8);
}
切勿**自行用 getBytes("GB2312") 等錯誤編碼再轉碼,會造成二次損壞。
public class EncodingTest {
public static void main(String[] args) {
System.out.println("file.encoding=" + System.getProperty("file.encoding"));
System.out.println("sun.jnu.encoding=" + System.getProperty("sun.jnu.encoding"));
System.out.println("defaultCharset=" + java.nio.charset.Charset.defaultCharset());
}
}
輸出皆為 UTF-8 即正確。
| 錯誤做法 | 後果 | 正確做法 |
|---|---|---|
new String(name.getBytes("GB2312"), "UTF-8") | 雙重錯誤編碼,資訊永久遺失 | JVM 啟動參數指定 UTF-8 |
| 依賴預設編碼 | 跨平台部署時行為不一致 | 顯式指定 StandardCharsets.UTF_8 |
只設 file.encoding | 檔案系統 API 仍可能亂碼 | 同時設 sun.jnu.encoding |
只要在 JVM 啟動階段鎖定 UTF-8,Linux 下 Java 處理中文檔名即可徹底告別亂碼。