Java не может открыть файл с суррогатными значениями Unicode в имени файла? - PullRequest
12 голосов
/ 09 октября 2009

Я имею дело с кодом, который выполняет различные операции ввода-вывода с файлами, и я хочу, чтобы он мог работать с международными именами файлов. Я работаю на Mac с Java 1.5, и если имя файла содержит символы Unicode, которые требуют суррогатов, JVM не может найти файл. Например, мой тестовый файл:

"草鷗外.gif", который разбивается на символы Java \u8349\uD85B\uDFF6\u9DD7\u5916.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

Есть ли какой-нибудь способ, которым я могу решить эту проблему, либо экранируя имена файлов, либо открывая файлы по-другому?

Ответы [ 4 ]

7 голосов
/ 10 октября 2009

Я подозреваю, что один из Java или Mac использует CESU-8 вместо надлежащего UTF-8. Java использует «модифицированный UTF-8» (что является небольшим изменением CESU-8) для различных внутренних целей, но я не знал, что он мог бы использовать его как файловую систему / defaultCharset. К сожалению, у меня нет ни Mac, ни Java для тестирования.

«Модифицированный» - это модифицированный способ сказать «сильно прослушивается». Вместо вывода четырехбайтовой последовательности UTF-8 для дополнительных (не BMP) символов, таких как & # x26FF6;:

\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) имя файла «草 & # x26FF6; 鷗 外 .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')
4 голосов
/ 09 октября 2009

Если язык вашей среды по умолчанию не содержит этих символов, вы не сможете открыть файл.

См .: File.exists () завершается с Unicode-символами в имени

Edit: Хорошо .. Что вам нужно, это изменить язык системы. Какую бы ОС вы не использовали.

Редактировать :

См .: Как открыть файлы, содержащие акценты в Java?

См .: JFileChooser на Mac не может видеть файлы, названные китайскими буквами?

3 голосов
/ 26 ноября 2009

Это оказалось проблемой с Mac JVM (протестировано на 1.5 и 1.6). Имена файлов, содержащие дополнительные пары символов / суррогатов, не могут быть доступны с помощью класса Java File. В итоге я написал библиотеку JNI с призывом Carbon для Mac-версии проекта (ick). Я подозреваю, что упоминается проблема с CESU-8, поскольку вызов JNI для получения символов UTF-8 вернул строку CESU-8. Не похоже, что это то, что вы действительно можете обойти.

0 голосов
/ 24 февраля 2014

Это ошибка в Java-файле old-skool api, может быть, только на Mac? В любом случае, новый java.nio api работает намного лучше. У меня есть несколько файлов, содержащих символы Юникода и контент, который не удалось загрузить с помощью java.io.File и связанных классов. После преобразования всего моего кода в java.nio.Path ВСЕ начало работать. И я заменил org.apache.commons.io.FileUtils (с той же проблемой) на java.nio.Files ...

... и обязательно прочитайте и запишите содержимое файла, используя соответствующий набор символов, например: Files.readAllLines (myPath, StandardCharsets.UTF_8)

...