Подтвердить что ты не робот

Java не может открыть файл с суррогатными значениями Unicode в имени файла?

Я имею дело с кодом, который выполняет различные операции ввода-вывода с файлами, и я хочу, чтобы он мог обрабатывать международные имена файлов. Я работаю над 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

Можно ли каким-то образом решить эту проблему, либо скрыть имена файлов, либо открыть файлы по-разному?

4b9b3361

Ответ 1

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

"Modified" is a modified way of saying "badly bugged". Instead of outputting a four-byte UTF-8 sequence for supplementary (non-BMP) characters like 𦿶:

\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('.')

On my filesystem (Linux, ext4, UTF-8), the filename "草𦿶鷗外.gif" comes out as:

['\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')

Ответ 2

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

Смотрите: Ошибка файла .exists() с символами unicode в имени

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

Изменить:

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

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

Ответ 3

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

Ответ 4

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

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