Понимание кодировки символов в типичном веб-приложении Java

Некоторый псевдокод:

String a = "A bunch of text"; //UTF-16
saveTextInDb(a); //Write to Oracle VARCHAR(15) column
String b = readTextFromDb(); //UTF-16
out.write(b); //Write to http response

Когда Вы сохраняете Java String (UTF-16) к Oracle VARCHAR (15) Oracle также хранит это как UTF-16? Длина VARCHAR Oracle относятся к количеству символов Unicode (и не числу байтов)?

Когда мы пишем b к ServletResponse это записало как UTF-16 или является нами преобразованием значения по умолчанию в другое кодирование как UTF-8?

5
задан Marcus Leon 28 March 2010 в 20:19
поделиться

3 ответа

Вместо UTF-16 подумайте "внутреннего представления" вашей строки. Строка в Java - это своего рода символы, вам все равно, какая кодировка используется внутри. Кодирование становится актуальным, если вы взаимодействуете с внешним миром программы. В вашем примере saveTextInDb, readTextFromDb и write делают это. Каждый раз, когда вы обмениваетесь строками с внешним миром, используется кодировка для преобразования. saveTextInDb (и читать) выглядят как самодельные методы, по крайней мере, я их не знаю. Поэтому вам следует посмотреть, какая кодировка используется для этих методов. Метод write модуля записи всегда создает байты, которые представляют кодировку, связанную с модулем записи. Если вы получаете свой Writer из HttpServletResponse, связанная кодировка используется для вывода ответа (который будет отправлен в заголовках).

response.setEncoding("UTF-8");
Writer out = response.getWriter();

Этот код возвращается без Writer, который переводит строки в кодировку UTF-8. Аналогично, если вы пишете в файл:

Writer fileout = new OutputStreamWriter(new FileOutputStream(myfile), "ISO8859-1");

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

4
ответ дан 13 December 2019 в 19:24
поделиться

ServletResponse по умолчанию будет использовать ISO 8859-1 (Latin 1). UTF-8 - это наиболее распространенная кодировка, используемая для HTTP-ответов, требующих Unicode, но вы должны установить эту кодировку специально.

Согласно этот документ Oracle может поддерживать UTF-8 или UTF-16 в базе данных. Ваши методы, которые читают / записывают Oracle, должны будут использовать соответствующую кодировку, которая соответствует настройке базы данных, и переводить ее во внутреннее представление Java или из него.

3
ответ дан 13 December 2019 в 19:24
поделиться

Возможность Oracle сохранять (и позже извлекать) текст Unicode из базы данных зависит только от набора символов базы данных (обычно указывается при создании базы данных) . Выбор AL32UTF8 в качестве набора символов рекомендуется для хранения текста Unicode в типах данных CHAR (включая VARCHAR / VARCHAR2), поскольку это позволит вам получить доступ ко всем кодовым точкам Unicode, не занимая много места для хранения по сравнению с другими кодировками, такими как AL16UTF16 / AL32UTF32.

Если это сделано, то именно драйвер Oracle JDBC отвечает за преобразование данных в кодировке UTF-16 в AL32UTF8.Это «автоматическое» преобразование между кодировками также происходит при чтении данных из базы данных. Чтобы ответить на запрос о длине байта VARCHAR, определение столбца VARCHAR2 в Oracle включает семантику байтов - VARCHAR2 (n) используется для определения столбца, который может хранить n байтов (это поведение по умолчанию, как указано параметром NLS_LENGTH_SEMANTICS базы данных); если вам нужно определить размер на основе символов, следует использовать VARCHAR2 (n CHAR).

Кодировка данных, записываемых в объект ServletResponse, зависит от кодировки символов по умолчанию, если это не указано через ServletResponse.setCharacterEncoding () или ServletResponse.setContentType () Вызовы API. В общем, для полного решения Unicode, включающего базу данных Oracle, необходимо знать

  1. кодировку входящих данных (т. Е. Кодировку данных, считываемых через объект ServletRequest). Это можно сделать, указав принятую кодировку в HTML-формах с помощью атрибута accept-charset . Если кодировка неизвестна, приложение может попытаться установить известное значение с помощью метода ServletRequest.setCharacterEncoding () . Этот метод не меняет существующую кодировку символов в потоке. Если входной поток находится в ISO-Latin1, указание другой кодировки, скорее всего, приведет к возникновению исключения.Знание кодировки важно, поскольку библиотеки времени выполнения Java потребуют знания исходной кодировки потока, если содержимое потока должно рассматриваться как символьные примитивы или строки. По-видимому, это требуется, когда вы вызываете ServletRequest.getParameter или аналогичные методы, которые будут обрабатывать поток и возвращать объекты String. В результате декодирования будут созданы символы в кодировке платформы (это UTF-16).
  2. Кодирование данных, считываемых из потоков, в отличие от данных, созданных с помощью JVM. Это очень важно, поскольку кодировку данных, считываемых из потоков, изменить нельзя. Однако существует процесс декодирования, который преобразует символы в поддерживаемых кодировках в символы UTF-16 всякий раз, когда к таким данным обращаются как к символьному примитиву или как к строке. С другой стороны, новые объекты String могут быть созданы с определенной кодировкой. Это имеет значение, когда вы записываете содержимое потока в другой поток (например, выходной поток объекта HttpServletResponse). Если содержимое входного потока обрабатывается как последовательность байтов, а не как символы или строки, тогда JVM не будет выполнять никаких операций декодирования. Это означало бы, что байты, записанные в выходной поток, не должны изменяться, если не созданы промежуточный символ или объекты String. В противном случае вполне возможно, что содержимое выходного потока будет искажено и неправильно проанализировано соответствующим декодером.Проще говоря,

    • , если кто-то записывает строковые объекты или символы в выходной поток сервлета, то необходимо указать кодировку, которую браузер должен использовать для декодирования ответа. Соответствующие кодировщики могут использоваться для кодирования последовательности символов, как указано в желаемом ответе.
    • если кто-то записывает последовательность байтов, которая будет интерпретироваться как символы,тогда кодировка, которая должна быть указана в заголовке HTTP, должна быть известна заранее
    • , если кто-то записывает последовательность байтов, которая будет анализироваться как последовательность байтов (для изображений и других двоичных данных), тогда концепция кодирования несущественный.
  3. Набор символов базы данных экземпляра Oracle. Как указывалось ранее, данные будут храниться в базе данных Oracle в определенном наборе символов (для типов данных CHAR). Драйвер Oracle JDBC обеспечивает преобразование данных между UTF-16 и AL32UTF8 (набор символов базы данных в данном случае) для типов данных CHAR и NCHAR. Когда вы вызываете resultSet.getString () , драйвер JDBC возвращает строку с символами UTF-16. Обратное верно, когда вы также отправляете данные в базу данных. Если используется другой набор символов базы данных, дополнительный уровень преобразования (из UTF-16 в UTF-8 в набор символов базы данных) выполняется прозрачно драйвером JDBC.
4
ответ дан 13 December 2019 в 19:24
поделиться
Другие вопросы по тегам:

Похожие вопросы: