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

Ошибка кодирования имени файла с Java 7 на OSX с помощью jnlp/webstart

У меня есть эта проблема, которая выпала на меня, и прошло несколько дней неудачных поисков и обходных попыток.

У меня теперь есть встроенная программа java swing, распространяемая jnlp/webstart, на компьютерах osx и windows, которая, среди прочего, загружает некоторые файлы из WebDav.

Недавно на тестовой машине с OSX 10.8 и Java 7 имена файлов и имена каталогов с акцентированными символами начали заменять их на вопросительные знаки.

Нет проблем с OSX с версиями Java до 7.

пример:

XXXYYY_è_ABCD/

становится

XXXYYY _? _ ABCD/

используя java.text.Normalizer (NFD, NFC, NFKD, NFKC) в исходной строке, результат отличается, но все еще не так:

XXXYYY_e? _ABCD/

или

XXXYYY_e_ABCD/

Я знаю, что из переписки между [andrew.brygin at oracle.com] и [mik3hall at gmail.com], что

Да, file.encoding устанавливается на основе языка, в котором работает jvm on, и если вы запустите свой java vm в xxxx.UTF-8 locale, file.encoding должен быть UTF-8, установленный в MacRoman, будет проблематичным. Поэтому я считаю, что Oracle/OpenJDK7 ведет себя правильно. Тем не менее, как Андрей Томпсон отметил, что если все предыдущие выпуски Apple JDK используют MacRoman как file.encoding для английского языка /UTF -8, существует "совместимость" здесь, возможно, стоит положить что-то в релиз, чтобы дать пользователям Oracle/OpenJDK MacOS хедз-ап.

оригинальная почта

from Joni Salonen блог (java-and-file-names-with-invalid-characters) Я знаю, что:

Вероятно, вы знаете, что Java использует "кодировку символов по умолчанию" для конвертировать двоичные данные в строки. Для чтения или записи текста с использованием другого вы можете использовать InputStreamReader или OutputStreamWriter. Но для конверсий данных в текст, глубоко в API, у вас нет выбора, кроме как для измените кодировку по умолчанию.

и

Как насчет file.encoding?

Системное свойство file.encoding также может использоваться для установки значения по умолчанию кодирование символов, которое Java использует для ввода-вывода. К сожалению, не влияют на то, как имена файлов декодируются в Строки.

выполнение локали изнутри неизменяемых последовательностей jnlp

LANG=
LC_COLLATE="C"
LC_CTYPE="C"
LC_MESSAGES="C"
LC_MONETARY="C"
LC_NUMERIC="C"
LC_TIME="C"
LC_ALL=

наиболее похожей проблемой для stackoverflow с решением является следующее: encoding-issues-on-java-7-file-names-in-os-x

но решение обертывает выполнение java-программы в script с помощью

#!/bin/bash
export LC_CTYPE="UTF-8" # Try other options if this doesn't work
exec java your.program.Here

но я не думаю, что этот параметр доступен мне из-за веб-старта, и я не нашел способа установить переменную среды LC_CTYPE из программы.

Любые решения или обходные пути?

P.S.:

Если мы запускаем программу непосредственно из оболочки, она корректно записывает файл/каталог даже на OSX 10 + Java 7. Проблема возникает только при использовании комбинации JNLP + OSX + Java7

4b9b3361

Ответ 1

Я не думаю, что сейчас существует реальное решение этой проблемы.

Тем временем я пришел к выводу, что переменные среды "C", напечатанные внутри программы, из песочницы Java Web Start, и (по дизайну, по-видимому) вы не можете влиять на тех, кто использует jnlp.

Принятый (принятый компанией) метод обхода/компромисса заключался в запуске jnlp с использованием javaws из bash script.

По-видимому, запуск jnlp из браузера или из finder создает новую среду песочницы с не установленным LANG (поэтому устанавливается на "C", что равно ASCII). Запуск jnlp из командной строки вместо этого выводит правильный LANG из системного значения по умолчанию, наследуя его от оболочки.

Это позволяет, по крайней мере, сохранить функцию автоопределения jnlp и зависимостей.

В любом случае, мы отправили отчет об ошибке в Oracle, но лично я не надеюсь, что он будет разрешен в ближайшее время, если когда-либо.

Ответ 2

Я считаю приемлемым иметь максимальное ASCII-представление имени файла, которое работает практически с любой кодировкой.

Сначала вы хотите использовать специально NFKD, чтобы максимальная информация сохранялась в форме ASCII. Например, "2⁵" становится "25", а не просто "2", "fi" становится "fi", а не "" и т.д., когда отфильтрованные символы не-ascii и non-control отфильтровываются.

String str = "XXXYYY_è_ABCD/";
str = Normalizer.normalize(str, Normalizer.Form.NFKD);
str = str.replaceAll( "[^\\x20-\\x7E]", "");
//The file name will be XXXYYY_e_ABCD no matter what system encoding

Затем вы всегда передавали имена файлов через этот фильтр, чтобы получить имя своей файловой системы. Вы теряете только некоторую уникальность, файл I.E asdé.txt - это то же самое как asde.txt, и в этой системе они не могут быть дифференцированы.

Ответ 3

EDIT: после экспериментов с OS X еще я понял, что мой ответ был абсолютно неправильным, поэтому я его переделываю.

Если ваша JVM поддерживает -Dfile.encoding=UTF-8 в командной строке JVM, это может устранить проблему. Я считаю, что это стандартное свойство, но я не уверен в этом.

HFS Plus, как и другие POSIX-совместимые файловые системы, хранит имена файлов в виде байтов. Но в отличие от Linux ext3 файловой системы, он заставляет имена файлов быть разложенными UTF-8. Это можно увидеть здесь с помощью интерпретатора Python в моей системе OS X, начиная с пустого каталога.

$ python
Python 2.7.1 (r271:86832, Jul 31 2011, 19:30:53) 
>>> import os
>>> os.mkdir('\xc3\xa8')
>>> os.mkdir('e\xcc\x80')
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
OSError: [Errno 17] File exists: 'e\xcc\x80'
>>> os.mkdir('\x8f')
>>> os.listdir('.')
['%8F', 'e\xcc\x80']
>>> ^D
$ ls
%8F è

Это доказывает, что имя каталога в вашей файловой системе не может быть закодировано в Mac-Roman (т.е. с байтовым значением 8F, где отображается è), при условии, что это файловая система HFS Plus. Но, конечно, JVM не уверен в файловой системе HFS Plus, а SMB и NFS не имеют одинаковых гарантий кодирования, поэтому JVM не должна принимать эту схему.

Поэтому вам нужно убедить JVM интерпретировать имена файлов и каталогов с кодировкой UTF-8, чтобы правильно прочитать имена как java.lang.String.

Ответ 4

Выстрел в темноте: Кодирование файлов не влияет на способ создания имен файлов, как содержимое записывается в файл - проверьте этого парня здесь: http://jonisalonen.com/2012/java-and-file-names-with-invalid-characters/

Вот короткая запись от Apple: http://developer.apple.com/library/mac/#qa/qa1173/_index.html

Сравнивая это с http://docs.oracle.com/javase/tutorial/i18n/text/normalizerapi.html Я бы предположил, что вы хотите использовать

normalized_string = Normalizer.normalize(target_chars, Normalizer.Form.NFD);

чтобы нормализовать имена файлов, прежде чем передавать их в конструктор Файла. Помогает ли это?

Ответ 5

Это ошибка в 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)