Проблема кодирования файлов платформы компилятора Java - PullRequest
8 голосов
/ 08 февраля 2011

Недавно я столкнулся с проблемой кодировки символов файла, с которой я никогда не сталкивался.Довольно часто нужно знать о кодировке символов текстовых файлов и писать код, который корректно обрабатывает кодирование при запуске на разных платформах.Но проблема, которую я обнаружил, была вызвана компиляцией на платформе, отличной от платформы исполнения.Это было совершенно неожиданно, потому что по моему опыту, когда javac создает файл класса, важными параметрами являются исходный и целевой параметры java, а также версия JDK, выполняющая компиляцию.В моем случае классы, скомпилированные с JDK 1.6.0_22 в Mac OS X, вели себя иначе, чем классы, скомпилированные с 1.6.0_23-b05 в Linux, при запуске в Mac OS X. Указанные источник и цель были 1.4.

Строка, которая была закодирована как ISO-8859_1 в памяти, была записана на диск с использованием метода PrintStream println.В зависимости от того, на какой платформе был скомпилирован код Java, строка была написана по-разному.Это привело к ошибке.Исправление этой ошибки заключалось в том, чтобы явно указывать кодировку файла при записи и чтении файла.

Меня удивило то, что поведение различалось в зависимости от того, где были скомпилированы классы, а не от того, на какой платформе был запущен класс.Я хорошо знаком с Java-кодом, который ведет себя по-разному при запуске на разных платформах.Но немного страшно, когда один и тот же код, скомпилированный на разных платформах, работает по-разному на одной и той же платформе .

Кто-нибудь сталкивался с этой конкретной проблемой?Казалось бы, это плохо для любого Java-кода, который читает и записывает строки в файл без явного указания кодировки символов.И как часто это делается?

Ответы [ 4 ]

7 голосов
/ 08 февраля 2011

Нет таких вещей, как a String, которая была закодирована как ISO-8859-1 в памяти . Строки Java в памяти всегда являются строками Unicode. (Закодировано в UTF-16, но сейчас вам это не нужно).

Кодирование вступает в действие только тогда, когда вы вводите или выводите строку - тогда, при отсутствии явного кодирования, используется системное значение по умолчанию (которое в некоторых системах зависит от пользовательских настроек).

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

  • Используйте опцию -encoding компилятора, предоставляя кодировку вашего исходного файла. (С помощью ant вы устанавливаете параметр encoding=.)
  • Используйте ваш редактор или любой другой инструмент (например, recode), чтобы изменить кодировку вашего файла на компилятор по умолчанию.
  • используйте native2ascii (с правой опцией -encoding), чтобы перевести ваш исходный файл в ASCII с \uXXXX -escapes.

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

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

Во всех проектах, которые у меня были в последние годы, я всегда кодирую все свои файлы в UTF-8, и в моем файле компоновки ant установите параметр encoding="utf-8" для задачи javac. (Мой редактор достаточно умен, чтобы автоматически распознавать кодировку, но я по умолчанию установил UTF-8.)

Кодировка имеет значение для других инструментов обработки исходного кода, таких как javadoc. (Там вы должны дополнительно опции -charset и -docencoding для вывода - они должны совпадать, но могут отличаться от источника- -encoding.)

4 голосов
/ 08 февраля 2011

Я бы рискнул предположить, что на этапе компиляции существует проблема с перекодировкой, и компилятору не хватает направления в отношении кодирования исходного файла (например, см. Переключатель javac -encoding).

Компиляторы обычно используют системную кодировку по умолчанию, если вы не конкретизируете, что может привести к повреждению строковых и символьных литералов (внутренне Java-байт-код использует измененную форму UTF-8, поэтому двоичные файлы переносимы). Это единственный способ представить, что проблемы возникают во время компиляции.

Я написал немного об этом здесь .

1 голос
/ 08 февраля 2011

Всегда используйте escape-коды (например, \uxxxx) в ваших исходных файлах, и это не будет проблемой.@ Пауло упомянул об этом, но я хотел прямо об этом сказать.

1 голос
/ 08 февраля 2011

У меня были похожие проблемы при использовании имен переменных, которые не являются ascii (Σ, σ, Δ и т. Д.) При выполнении математической формулы.В Linux для интерпретации использовалась кодировка UTF-8.На Windows он жаловался на недопустимые имена, потому что Windows использует ISO-LATIN-1.Решением было указать кодировку в ant-скрипте, который я использовал для компиляции этих файлов.

...