Как задать кодировку файла java

Обновлено: 06.07.2024

Кодовые точки Unicode и русские символы в исходных кодах и программах Java . JDK 1.6.

Статья опубликована: 06.11.2006

Последнее обновление : 18.03.2007

Достаточно много разработчиков программного обеспечения в действительности не имеют до конца четкого представления о наборах символов, кодировок, Unicode и сопутствующих материалах. Даже в настоящее время многими программами часто игнорируются встречающиеся преобразования символов, даже программами, которые, казалось бы, разработаны с помощью дружественных к Unicode Java технологиях . Зачастую беспечно используется для символов 8 битов, что делает невозможным разработку хороших многоязычных web-приложений. Данная статья является объединением рядов статей по вопросам кодировки Unicode , однако основополагающей стала переработанная статья Джоэла Сполски The Absolute Minimum Every Software Developer Absolutely , Positively Must Know About Unicode and Character Sets (08.10.2003).

История создания различных видов кодировок

В конечном счете, разнообразие кодировок OEM было сведено в стандарт ANSI. Стандарт ANSI, оговаривал, какие символы располагались ниже 128, эта область в основном оставалась той же, что и в ASCII, но было много различных способов обращаться с символами от 128 и выше в зависимости от того, где вы жили. Эти различные системы назвали кодовыми страницами. Так, например, в Израиле DOS использовал кодовую страницу с номером 862, в то время как греческие пользователи использовали страницу с номером 737. Они были одними и теми же ниже 128, но отличались от 128, где и находились все эти символы. Национальные версии MS-DOS поддерживали множество этих кодовых страниц, обращаясь со всеми языками, начиная с английского и заканчивая исландским, и было даже несколько "многоязычных" кодовых страниц, которые могли сделать Эсперанто и Галисийский (прим. пер. :г алисийский язык относится к романской группе языков, распространён в Испании, носителей 4 млн. чел) на одном и том же компьютере! Но получить, скажем, иврит и греческий на одном и том же компьютере было абсолютно невозможно, если только вы не написали вашу собственную программу, которая показывала все, используя графику с побитовым отображением, потому что для еврейского и греческого требовались различные кодовые страницы с различными интерпретациями старших чисел.

Тем временем в Азии, принимая во внимание тот факт, что азиатские алфавиты имеют тысячи букв, которые никогда бы не смогли уместиться в 8 битов, эта проблема решалась запутанной системой DBCS, "двухбайтовый набор символов" ( double byte character set ), в котором некоторые символы сохранялись в одном байте, а другие занимали два. Было очень легко передвигаться по строке вперед, но абсолютно невозможно передвигаться назад. Программисты не могли использовать для перемещения вперед и назад s++ и s -- , и вместо этого должны были вызывать специальные функции, которые знали, как иметь дело с этим беспорядком.

Тем не менее, большинство людей закрывало глаза на то, что байт был символом и символ был 8 битами и, пока вам не приходилось перемещать строку с одного компьютера на другой, или если вы не говорили больше, чем на одном языке, это работало. Но, конечно, как только массово стал использоваться Интернет, стало весьма обычным делом переносить строки с одного компьютера на другой. Хаос в этом вопросе был преодолен с помощью Unicode .

Unicode был смелой попыткой создать единственный набор символов, который включал бы все реальные системы письма, существующие на планете, а также некоторые выдуманые . Некоторые люди имеют неправильное представление, что Unicode – это обычный 16-битовый код, где каждый символ занимает 16 битов и поэтому есть 65,536 возможных символов. На самом деле это не верно. Это самый распространенное ошибочное представление о Unicode .

Фактически, Unicode содержит необычный подход к пониманию понятия символ. До сих пор мы предполагали, что символы отображаются на набор каких-то битов, которые вы можете хранить на диске или в памяти:

В Unicode символ отображается на нечто, называемое кодовой точкой ( code point ), которая является всего лишь теоретическим понятием. Как эта кодовая точка представлена в памяти или на диске — это отдельная история. В Unicode буква A это всего лишь платонова идея ( эйдос ) (прим. пер.: понятие философии Платона, эйдосы – это идеальные сущности, лишённые телесности и являющиеся подлинно объективной реальностью, находящиеся вне конкретных вещей и явлений).

A Э та платонова A отличается от B , и отличается от a , но это та же самая A , что и A и A . Идея, что А в шрифте Times New Roman является тем же самым, что и А в шрифте Helvetica , но отличается от строчной " a ", не кажется слишком спорной в понимании людей. Но с точки зрения компьютерных наук и с точки зрения языка само определение буквы противоречиво. Немецкая буква ß – это настоящая буква или всего лишь причудливый способ написать ss ? Если написание буквы, стоящей в конце слова, изменяется, она становится другой буквой? Иврит говорит да, арабский говорит нет. Так или иначе, умные люди в консорциуме Unicode поняли это, после большого количества политических дебатов, и вы не должны волноваться об этом. Все уже понято до нас.

Каждой платоновой букве в каждом алфавите консорциумом Unicode было назначено волшебное число, которое записывается так, как это: U+0645. Это волшебное число называют кодовой точкой. U+ означает " Unicode ", а числа являются шестнадцатеричными. Число U+FEC9 является арабской буквой Аин ( Ain ). Английская буква A соответствует U+0041.

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

Для кириллицы в UNICODE отведен диапазон кодов от 0x0400 до 0x04FF. В данной таблице приведена лишь часть знаков этого диапазона, однако стандартом определено большинство кодов этого диапазона.

Представим, что мы имеем строку:

которая , в Unicode , соответствует этим семи кодовым точкам:

U+ 041 F U+0440 U+0438 U+0432 U+0435 U+0442 U+0021

Всего лишь набор кодовых точек. Числа в действительности.

Чтобы узнать, как будет выглядеть текстовый файл в формате Unicode , можно запустить программу notepad в Windows , вставить данную строку и при сохранении текстового файла выбрать кодировку Unicode .

Программа предлагает сохранение в трех разновидностях кодировок Unicode . Первый вариант представляет собой способ записи с младшим байтом впереди ( little endian ), второй со старшим байтом впереди ( big endian ). Какой из вариантов является правильным?

Вот как выглядит дамп файла со строкой “ Привет! ”, сохраненный в формате Unicode ( big endian ):


А так выглядит дамп файла со строкой “ Привет! ”, сохраненный в формате Unicode ( little endian ):


А так выглядит дамп файла со строкой “ Привет! ”, сохраненный в формате Unicode ( UTF -8):


Ранние реализации хотели быть в состоянии хранить кодовые точки Unicode в формате с первым старшим байтом и первым младшим байтом ( high-endian or low-endian ), в зависимости от того, с каким форматом именно их процессор работал быстрее. Тогда возникло два способа хранить Unicode . Это привело к появлению причудливого соглашения о хранении кода \ uFFFE в начале каждой строки Unicode . Эту сигнатуру называют меткой порядка байтов ( byte order mark ). Если вы поменяете местами ваши старший и младший байты, то в начале должно стоять \ uFFFE , и человек, читающий вашу строку, будет знать, что он должен поменять байты в каждой паре местами. Данная сигнатура является зарезервированной в стандарте Unicode .

В стандарте Unicode написано, что порядок байт по умолчанию является либо big endian , либо little endian . Действительно, оба порядка являются правильным, и разработчики систем сами выбирают себе один из них. Не стоит беспокоиться, если ваша система обменивается данными с другой системой и обе используют little endian .

Однако , если ваша Windows обменивается данными с UNIX-сервером, который использует big endian , одна из систем должна осуществлять перекодировку. В этом случае стандарт Unicode гласит, что можно выбрать любой из следующих способов решения проблемы:

1. Когда две системы, использующие различный порядок представления байт в Unicode , обмениваются данными (не используя каких-то специальных протоколов), то порядок байт должен быть big endian . В стандарте это называется каноническим ( canonical ) порядком байт.

2. Каждая строка Unicode должна начинаться с кода \ uFEFF . Код \ uFFFE , который является “перевертыванием” знака порядка. Поэтому если получатель видит в качестве первого символа код \ uFEFF , то это значит, что байты находятся в перевернутом ( little endian ) порядке. Тем не менее, в реальности, не каждая строка Unicode имеет в начале метку порядка байтов.

Второй способ является более универсальным и предпочтительным.

Некоторое время казалось, что все довольны, но англоязычные программисты рассматривали в основном английский текст и редко использовали кодовые точки выше U+00FF. По одной только этой причине Unicode многими игнорировался в течение нескольких лет.

Специально для этого была изобретена блестящая концепция UTF-8 .

UTF -8

UTF-8 был другой системой хранения вашей последовательности кодовых точек Unicode , тех самых U+ чисел, используя те же 8 битов в памяти. В UTF-8 каждая кодовая точка с номерами от 0 до 127 сохранялись в единственном байте.

По сути, это кодировка с переменным количеством кодирующих байтов для хранения используется 2, 3, и, фактически, до 6 байтов. Если символ принадлежит набору ASCII (код в интервале 0x00-0x7F), то он кодируется так же как в ASCII одним байтом. Если юникод символа больше или равен 0x80, то его биты упаковываются в последовательность байтов по следующему правилу:

Как правильно установить кодировку символов по умолчанию, используемую JVM (1.5.х) программно?

Я читал, что -Dfile.encoding=whatever раньше был способ пойти для старых JVMs. У меня нет такой роскоши по причинам, в которые я не хочу вдаваться.

и свойство устанавливается, но это, похоже, не вызывает окончательный вызов getBytes ниже, чтобы использовать UTF8:

к сожалению, file.encoding свойство должно быть указано при запуске JVM; к моменту ввода основного метода кодировка символов, используемая String.getBytes() и конструкторы по умолчанию InputStreamReader и OutputStreamWriter постоянно кэшируется.

As Эдвард грех указывает, в частном случае, как это, переменная окружения JAVA_TOOL_OPTIONS can используется для указания этого свойства, но обычно это делается так это:

Charset.defaultCharset() будет отражать изменения file.encoding свойство, но большинство кода в основных библиотеках Java, которые должны определить кодировку символов по умолчанию, не используют этот механизм.

когда вы кодируете или декодируете, вы можете запросить file.encoding собственность или Charset.defaultCharset() чтобы найти текущую кодировку по умолчанию и использовать соответствующий метод или перегрузку конструктора, чтобы указать ее.

поскольку командная строка не всегда может быть доступна или изменена, например, во встроенных VMs или просто VMs, запущенных глубоко в сценариях, a JAVA_TOOL_OPTIONS переменная предоставляется так, что агенты могут быть запущены в этих случаях.

Picked up JAVA_TOOL_OPTIONS: -Dfile.encoding=UTF8

У меня есть хакерский способ, который определенно работает!!

таким образом, вы собираетесь обмануть JVM, который будет думать, что charset не установлен и сделать это, чтобы установить его снова в UTF-8, во время выполнения!

Я думаю, что лучший подход, чем установка набора символов платформы по умолчанию, тем более, что у вас, похоже, есть ограничения на влияние на развертывание приложения, не говоря уже о платформе, - это вызвать гораздо более безопасный String.getBytes("charsetName") . Таким образом, ваше приложение не зависит от вещей, находящихся вне его контроля.

Я лично считаю, что String.getBytes() должно быть устаревшим, так как это вызвало серьезные проблемы в ряде случаев, которые я видел, когда разработчик не учитывал значение по умолчанию кодировка, возможно, меняется.

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

Изучите кодировку символов в Java и узнайте о распространенных подводных камнях.

1. Обзор

В этом уроке мы обсудим основы кодирования символов и то, как мы справляемся с этим в Java.

2. Важность кодирования символов

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

Чтобы сделать это правильно, нам нужно подумать о кодировке символов. Невыполнение этого требования часто может привести к потере данных и даже уязвимостям безопасности.

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

Обратите внимание, что вводимый здесь текст использует кодировку платформы по умолчанию.

Ну, не совсем то, что мы ожидали.

3. Основы

Однако, прежде чем копать глубже, давайте быстро рассмотрим три термина: кодировка , кодировка и кодовая точка .

3.1. Кодирование

Компьютеры могут понимать только двоичные представления, такие как 1 и 0 . Обработка всего остального требует некоторого сопоставления текста реального мира с его двоичным представлением. Это отображение-то, что мы знаем как кодировка символов или просто как кодировка .

3.2. Кодировки

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

3.3. Кодовый пункт

Мы можем представить само целое число в простых десятичных или альтернативных основаниях, таких как шестнадцатеричное или восьмеричное. Мы используем альтернативные базы для удобства ссылки на большие числа.

4. Понимание Схем Кодирования

Кодировка символов может принимать различные формы в зависимости от количества символов, которые она кодирует.

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

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

4.1. Однобайтовое кодирование

Одна из самых ранних схем кодирования, называемая ASCII (Американский стандартный код для обмена информацией), использует однобайтовую схему кодирования. По сути, это означает, что каждый символ в ASCII представлен семибитными двоичными числами. Это все еще оставляет один бит свободным в каждом байте!

Давайте определим простой метод в Java для отображения двоичного представления символа в определенной схеме кодирования:

И если мы используем наш метод утилиты, мы можем увидеть его двоичное представление:

Исходный ASCII оставил самый значимый бит каждого байта неиспользованным. В то же время ASCII оставил довольно много непредставленных символов,

Исходный ASCII оставил самый значимый бит каждого байта неиспользованным. || В то же время ASCII оставил довольно много непредставленных символов,

Было предложено и принято несколько вариантов схемы кодирования ASCII.

Многие расширения ASCII имели разные уровни успеха, но, очевидно, это

4.2. Многобайтовое кодирование

Поскольку потребность в размещении все большего количества символов росла, однобайтовые схемы кодирования, такие как ASCII, не были устойчивыми.

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

BIG 5 и SHIFT-JIS являются примерами многобайтовых схем кодирования символов, которые начали использовать как один, так и два байта для представления более широких наборов символов . Большинство из них были созданы для того, чтобы представлять китайские и аналогичные сценарии, которые имеют значительно большее количество символов.

полный список кодировок символов, наряду с их псевдонимами, ведется Международным органом по номерам.

5. Юникод

Нетрудно понять, что, хотя кодирование важно, декодирование в равной степени жизненно важно для понимания представлений. Это возможно на практике только в том случае, если широко используется согласованная или совместимая схема кодирования.

Различные схемы кодирования, разработанные изолированно и практикуемые в местных географических регионах, начали становиться сложными.

Эта проблема породила особый стандарт кодирования, называемый Unicode, который имеет емкость для всех возможных символов в мире . Это включает в себя символы, которые используются, и даже те, которые уже не существуют!

Ну, для этого должно потребоваться несколько байтов для хранения каждого символа? Честно говоря, да, но у Unicode есть гениальное решение.

Мы используем шестнадцатеричную систему в качестве основы для кодовых точек в Юникоде, поскольку существует 1 114 112 точек, что является довольно большим числом для удобной передачи в десятичном формате!

То, как эти кодовые точки кодируются в биты, зависит от конкретных схем кодирования в Юникоде. Мы рассмотрим некоторые из этих схем кодирования в подразделах ниже.

5.1. UTF-32

UTF-32-это схема кодирования для Unicode, которая использует четыре байта для представления каждой кодовой точки , определенной Unicode. Очевидно, что использование четырех байтов для каждого символа неэффективно.

5.2. UTF-8

Вывод в точности аналогичен ASCII, использующему только один байт. На самом деле UTF-8 полностью обратно совместим с ASCII.

UTF-8, благодаря своей экономичности пространства, является наиболее распространенной кодировкой, используемой в Интернете.

6. Поддержка кодирования в Java

Java поддерживает широкий спектр кодировок и их преобразования друг в друга. Класс Charset определяет набор стандартных кодировок , которые должна поддерживать каждая реализация платформы Java.

Это включает в себя US-ASCII, ISO-8859-1, UTF-8 и UTF-16, чтобы назвать некоторые из них. Конкретная реализация Java может дополнительно поддерживать дополнительные кодировки .

Есть некоторые тонкости в том, как Java подбирает кодировку для работы. Давайте рассмотрим их более подробно.

6.1. Кодировка по умолчанию

Платформа Java сильно зависит от свойства, называемого кодировкой по умолчанию . Виртуальная машина Java (JVM) определяет кодировку по умолчанию во время запуска .

Это зависит от локали и кодировки базовой операционной системы, на которой работает JVM. Например, в macOS кодировка по умолчанию-UTF-8.

Давайте посмотрим, как мы можем определить кодировку по умолчанию:

Если мы запустим этот фрагмент кода на компьютере с Windows, то получим результат:

6.2. Кто использует Кодировку по умолчанию?

Многие API Java используют кодировку по умолчанию, определенную JVM. Чтобы назвать несколько:

  • InputStreamReader и Средство чтения файлов
  • OutputStreamWriter и Файловая машина
  • Форматер и Сканер
  • URLEncoder и URLDecoder

Итак, это означает, что если бы мы запустили наш пример без указания кодировки:

затем он будет использовать кодировку по умолчанию для ее декодирования.

И есть несколько API, которые делают этот же выбор по умолчанию.

Таким образом, кодировка по умолчанию приобретает важность, которую мы не можем безопасно игнорировать.

6.3. Проблемы С Набором Символов По Умолчанию

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

Например, если мы запустим

в macOS он будет использовать UTF-8.

Если мы попробуем тот же фрагмент кода в Windows, он будет использовать Windows-1252 для декодирования того же текста.

Или представьте, что вы пишете файл в mac OS, а затем читаете тот же файл в Windows.

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

6.4. Можем ли мы переопределить кодировку по умолчанию?

Определение кодировки по умолчанию в Java приводит к двум системным свойствам:

  • file.encoding : Значение этого системного свойства является именем набора символов по умолчанию
  • sun.jnu.encoding : Значением этого системного свойства является имя набора символов, используемого при кодировании/декодировании путей к файлам

Теперь интуитивно понятно переопределять эти системные свойства с помощью аргументов командной строки:

Однако важно отметить, что эти свойства доступны только для чтения в Java. Их использование, как указано выше, отсутствует в документации . Переопределение этих системных свойств может не иметь желаемого или предсказуемого поведения.

Следовательно, мы должны избегать переопределения кодировки по умолчанию в Java .

6.5. Почему Java Не Решает Эту Проблему?

Этот ДЖИП находится в состоянии проекта на данный момент и когда он (надеюсь!) пройдя через него, мы решим большинство вопросов, которые мы обсуждали ранее.

Обратите внимание, что более новые API, такие как в файле java.nio.file.Файлы не используют кодировку по умолчанию. Методы в этих API-интерфейсах читают или записывают символьные потоки с кодировкой UTF-8, а не с кодировкой по умолчанию.

6.6. Решение Этой Проблемы в Наших Программах

Обычно мы должны выбирать кодировку при работе с текстом, а не полагаться на настройки по умолчанию . Мы можем явно объявить кодировку, которую мы хотим использовать в классах, которые имеют дело с преобразованием символов в байты.

К счастью, наш пример уже определяет кодировку. Нам просто нужно выбрать правильный, и пусть Java сделает все остальное.

Бинго! Мы можем увидеть результат, который мы надеялись увидеть.

Здесь мы установили кодировку, которая, по нашему мнению, лучше всего соответствует нашим потребностям в конструкторе InputStreamReader . Обычно это самый безопасный метод работы с символами и преобразованиями байтов в Java.

Аналогично, OutputStreamWriter и многие другие API поддерживают настройку схемы кодирования через свой конструктор.

6.7. Исключение MalformedInputException

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

Существует три предопределенные стратегии (или CodingErrorAction ), когда входная последовательность имеет искаженные входные данные:

  • ИГНОРИРОВАТЬ будет игнорировать искаженные символы и возобновит операцию кодирования
  • REPLACE заменит искаженные символы в выходном буфере и возобновит операцию кодирования
  • ОТЧЕТ вызовет исключение MalformedInputException

По умолчанию malformedInputAction для кодера CharsetDecoder является REPORT, и по умолчанию malformedInputAction декодера по умолчанию в InputStreamReader is REPLACE.

Давайте определим функцию декодирования , которая получает заданную кодировку , тип CodingErrorAction и строку, подлежащую декодированию:

Для второго теста мы используем CodingErrorAction.ЗАМЕНИТЕ , который помещает � вместо запрещенных символов:

Для третьего теста мы используем CodingErrorAction.ОТЧЕТ который приводит к выбрасыванию MalformedInputException:

7. Другие Места, Где Кодирование Важно

Нам не просто нужно учитывать кодировку символов при программировании. Тексты могут окончательно испортиться во многих других местах.

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

Давайте быстро рассмотрим несколько мест, где мы можем столкнуться с проблемами при кодировании или декодировании текста.

7.1. Текстовые Редакторы

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

7.2. Файловая система

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

7.3. Сеть

Тексты, передаваемые по сети с использованием протокола, такого как протокол передачи файлов (FTP), также включают преобразование между кодировками символов. Для всего, что закодировано в Юникоде, безопаснее всего передавать в двоичном виде, чтобы свести к минимуму риск потери при преобразовании. Однако передача текста по сети является одной из менее частых причин повреждения данных.

7.4. Базы данных

Большинство популярных баз данных, таких как Oracle и MySQL, поддерживают выбор схемы кодирования символов при установке или создании баз данных. Мы должны выбрать это в соответствии с текстами, которые мы ожидаем сохранить в базе данных. Это одно из наиболее частых мест, где повреждение текстовых данных происходит из-за преобразования кодировки.

7.5. Браузеры

Наконец, в большинстве веб-приложений мы создаем тексты и пропускаем их через различные слои с намерением просмотреть их в пользовательском интерфейсе, например в браузере. Здесь также важно, чтобы мы выбрали правильную кодировку символов, которая может правильно отображать символы. Большинство популярных браузеров, таких как Chrome, Edge, позволяют выбирать кодировку символов в своих настройках.

8. Заключение

В этой статье мы обсудили, как кодирование может быть проблемой при программировании.

Далее мы обсудили основные принципы, включая кодировку и кодировки. Более того, мы прошли через различные схемы кодирования и их использование.

Мы также подобрали пример неправильного использования кодировки символов в Java и увидели, как это сделать правильно. Наконец, мы обсудили некоторые другие распространенные сценарии ошибок, связанные с кодировкой символов.

Мне нужно, чтобы UTF-8 работал в моем веб-приложении Java (сервлеты + JSP, среда не использовалась) для поддержки äöå и т. Д. Для обычного финского текста и кириллицы, например, ЦжФ для особых случаев.

Моя установка следующая:

  • Среда разработки: Windows XP
  • Производственная среда: Debian

Используемая база данных: MySQL 5.x

Пользователи в основном используют Firefox2, но также для доступа к сайту используются Opera 9.x, FF3, IE7 и Google Chrome.

Как этого добиться?

Отвечая на себя как часто задаваемые вопросы этого сайта поощряет это. Это работает для меня:

В основном, символы не являются проблематичными, поскольку набор символов по умолчанию, используемый браузерами, а tomcat / java для веб-приложений - latin1, т.е. ISO-8859-1, который "понимает" эти символы.

Для работы UTF-8 под Java + Tomcat + Linux / Windows + Mysql требуется следующее:

Конфигурирование сервера Tomcat server.xml

Необходимо настроить, чтобы соединитель использовал UTF-8 для кодирования параметров url (GET request):

Ключевой частью является URIEncoding = "UTF-8" в вышеприведенном примере. Это гарантирует, что Tomcat обрабатывает все входящие параметры GET в кодировке UTF-8. В результате, когда пользователь пишет в адресную строку браузера следующее:

символ is обрабатывается как UTF-8 и кодируется (обычно браузером перед тем, как даже попасть на сервер) как % D0% B6 .

На запрос POST это не влияет.

CharsetFilter

Затем пришло время заставить приложение Java обрабатывать все запросы и ответы в кодировке UTF-8. Для этого необходимо определить фильтр набора символов следующим образом:

Этот фильтр гарантирует, что если браузер не установил кодировку, используемую в запросе, он установлен в UTF-8.

Другая вещь, которую делает этот фильтр, заключается в установке кодировки ответа по умолчанию, т.е. кодировка, в которой возвращается html / что угодно. Альтернативой является установка кодировки ответа и т. Д. В каждом контроллере приложения.

Этот фильтр необходимо добавить в файл web.xml или дескриптор развертывания веб-приложения:

JSP кодирование страницы

В вашем web.xml добавьте следующее:

В качестве альтернативы, на всех JSP-страницах веб-приложения должно быть следующее:

Если используется какая-то компоновка с разными JSP-фрагментами, то это необходимо во всех из них.

HTML-мета-теги

Кодировка страницы JSP говорит JVM обрабатывать символы на странице JSP в правильной кодировке. Затем пришло время сообщить браузеру, в какой кодировке находится HTML-страница:

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

JDBC-соединение

При использовании БД необходимо определить, что соединение использует кодировку UTF-8. Это делается в context.xml или там, где соединение JDBC определяется следующим образом:

MySQL база данных и таблицы

Используемая база данных должна использовать кодировку UTF-8. Это достигается путем создания базы данных со следующим:

Затем все таблицы должны быть в UTF-8:

Ключевой частью является CHARSET = utf8 .

Конфигурация сервера MySQL

MySQL serveri также должен быть настроен. Обычно это делается в Windows путем изменения my.ini -file, а в Linux - путем настройки my.cnf -file. В этих файлах должно быть определено, что все клиенты, подключенные к серверу, используют utf8 в качестве набора символов по умолчанию и что набор символов по умолчанию, используемый сервером, также является utf8.

Mysql процедуры и функции

Они также должны иметь определенный набор символов. Например:

GET запросы: latin1 и UTF-8

Если и когда в tomcat server.xml определено, что параметры запроса GET кодируются в UTF-8, следующие запросы GET обрабатываются правильно:

Поскольку ASCII-символы кодируются одинаково как с помощью latin1, так и UTF-8, строка «Petteri» обрабатывается правильно.

Символ кириллицы ж вообще не понимается в латинице1. Поскольку Tomcat получает указание обрабатывать параметры запроса как UTF-8, он правильно кодирует этот символ как % D0% B6 .

Если и когда браузеры проинструктированы читать страницы в кодировке UTF-8 (с заголовками запросов и метатегом html), по крайней мере, Firefox 2/3 и другие браузеры этого периода сами кодируют символ как % D0% B6 .

Конечным результатом является то, что все пользователи с именем "Petteri" найдены, а также все пользователи с именем "ж" найдены.

Но как насчет?

в зашифрованной версии

В латинице 1 символ ä кодируется как % E4 . Хотя страница / запрос / все определено для использования UTF-8 . Версия ä в кодировке UTF-8: % C3% A4

В результате этого веб-приложение не может корректно обрабатывать параметры запроса из запросов GET, поскольку некоторые символы кодируются в латинице 1, а другие - в UTF-8. Примечание: запросы POST работают, так как браузеры полностью кодируют все параметры запроса из форм в UTF-8, если страница определена как UTF-8.

Материал для чтения

Большое спасибо авторам следующих статей за ответы на мою проблему:

Важная заметка

MySQLподдерживает базовую многоязычную плоскость, используя 3-байтовые символы UTF-8. Если вам нужно выйти за пределы этого (некоторые алфавиты требуют более 3 байтов UTF-8), то вам нужно либо использовать VARBINARY тип столбца, либо использовать utf8mb4 набор символов (для этого требуется MySQL 5.5.3 или более поздняя версия). Просто помните, что использование utf8 набора символов в MySQL не будет работать 100% времени.

Tomcat с Apache

Еще одна вещь Если вы используете коннектор Apache + Tomcat + mod_JK, вам также необходимо внести следующие изменения:

Читайте также: