簡體   English   中英

Java 無法打開文件名中包含代理 Unicode 值的文件?

[英]Java Can't Open a File with Surrogate Unicode Values in the Filename?

我正在處理對文件執行各種 IO 操作的代碼,我想讓它能夠處理國際文件名。 我正在使用 Java 1.5 的 Mac 上工作,如果文件名包含需要代理的 Unicode 字符,則 JVM 似乎無法找到該文件。 例如,我的測試文件是:

破解成Java字符\草\?\?\鷗\外.gif "草鷗外.gif"

如果我從此文件名創建文件,則無法打開它,因為出現 FileNotFound 異常。 即使在包含文件的文件夾上使用它也會失敗:

File[] files = folder.listFiles(); 
for (File file : files) {
    if (!file.exists()) {
        System.out.println("Failed to find File"); //Fails on the surrogate filename
    }
}

我實際處理的大部分代碼都是以下形式:

FileInputStream instream = new FileInputStream(new File("草鷗外.gif"));
// operations follow

有什么方法可以解決這個問題,要么轉義文件名,要么以不同方式打開文件?

我懷疑 Java 或 Mac 之一正在使用CESU-8而不是正確的 UTF-8。 Java 使用“修改后的 UTF-8”(這是 CESU-8 的輕微變體)用於各種內部目的,但我不知道它可以將它用作文件系統/defaultCharset。 不幸的是,我這里既沒有 Mac 也沒有 Java 可以測試。

“Modified”是“badly bugged”的一種修改方式。 而不是為像𦿶這樣的補充(非 BMP)字符輸出一個四字節的 UTF-8 序列:

\xF0\xA6\xBF\xB6

它為每個代理輸出一個 UTF-8 編碼的序列:

\xED\xA1\x9B\xED\xBF\xB6

這不是有效的 UTF-8 序列,但無論如何很多解碼器都會允許它。 問題是,如果您通過真正的 UTF-8 編碼器來回傳輸,您會得到一個不同的字符串,即上面的四字節字符串。 嘗試訪問具有該名稱的文件並繁榮! 失敗。

所以首先讓我們檢查文件名是如何實際存儲在當前文件系統下的,使用一個使用字節作為文件名的平台,例如 Python 2.x:

$ python
Python 2.x.something (blah blah)
Type "help", "copyright", "credits" or "license" for more information.
>>> import os
>>> os.listdir('.')

在我的文件系統(Linux、ext4、UTF-8)上,文件名“草𦿶鷗外.gif”顯示為:

['\xe8\x8d\x89\xf0\xa6\xbf\xb6\xe9\xb7\x97\xe5\xa4\x96.gif']

這就是你想要的。 如果這就是你得到的,那很可能是 Java 做錯了。 如果您獲得更長的六字節字符版本:

['\xe8\x8d\x89\xed\xa1\x9b\xed\xbf\xb6\xe9\xb7\x97\xe5\xa4\x96.gif']

這可能是 OS X 做錯了……它總是存儲這樣的文件名嗎? (或者文件最初來自其他地方嗎?)如果您將文件重命名為“正確”版本怎么辦?:

os.rename('\xe8\x8d\x89\xed\xa1\x9b\xed\xbf\xb6\xe9\xb7\x97\xe5\xa4\x96.gif', '\xe8\x8d\x89\xf0\xa6\xbf\xb6\xe9\xb7\x97\xe5\xa4\x96.gif')

如果您環境的默認語言環境不包含這些字符,您將無法打開該文件。

請參閱: File.exists() 失敗,名稱中包含 unicode 字符

編輯:好的..您需要的是更改系統區域設置。 無論您使用什么操作系統。

編輯

請參閱: 如何在 Java 中打開包含重音符號的文件?

請參閱: Mac 上的 JFileChooser 看不到以中文字符命名的文件?

結果證明這是 Mac JVM 的問題(在 1.5 和 1.6 上測試)。 不能使用 Java File 類訪問包含補充字符/代理項對的文件名。 我最終編寫了一個 JNI 庫,其中包含針對 Mac 版本項目 (ick) 的 Carbon 調用。 我懷疑 bobince 提到的 CESU-8 問題,因為獲取 UTF-8 字符的 JNI 調用返回了 CESU-8 字符串。 看起來這不是你可以真正解決的問題。

這是 old-skool java File api 中的一個錯誤,也許只是在 mac 上? 無論如何,新的 java.nio api 工作得更好。 我有幾個包含 unicode 字符和內容的文件,這些文件無法使用 java.io.File 和相關類加載。 將我所有的代碼轉換為使用java.nio.Path 后,一切都開始工作了。 我用java.nio.Files替換了 org.apache.commons.io.FileUtils (有同樣的問題)...

...並確保使用適當的字符集讀取和寫入文件的內容,例如: Files.readAllLines(myPath, StandardCharsets.UTF_8)

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM