1. Процесс преобразования кодирования Java
Мы всегда используем файл класса Java для взаимодействия с пользователями наиболее напрямую (вход, вывод), и текст, содержащийся в этом интерактивном контенте, может содержать китайский. Независимо от того, взаимодействуют ли эти классы Java с базой данных или с линейной страницей, их жизненный цикл всегда такой:
(1) Программисты записывают код программы через редактор в операционной системе и сохраняют операционную систему в формате .java. Мы называем эти файлы исходными файлами.
(2) Составьте эти исходные файлы через javac.exe в JDK, чтобы сформировать класс .class.
(3) Запустите эти классы напрямую или разверните их в веб -контейнере, чтобы получить результат вывода.
Эти процессы наблюдаются с точки зрения макроса, и определенно невозможно понять это. Нам нужно по -настоящему понять, как Java кодирована и декодирована:
Шаг 1: Когда мы используем редактор для написания исходного файла Java, файл программы будет использовать формат кодирования по умолчанию операционной системы (обычно наша китайская операционная система использует формат кодирования GBK) для формирования файла .java. Исходный файл Java сохраняется в формате кодирования File.encoding по умолчанию. Следующий код может просмотреть значение параметра системы.
System.out.println (System.getProperty ("file.encoding")); Шаг 2: Когда мы используем javac.exe для составления нашего файла Java, JDK сначала подтвердит кодирование параметров компиляции для определения набора символов исходного кода. Если мы не указам параметр компиляции, JDK сначала получит параметр файла по умолчанию операционной системы. Кодирование, а затем JDK преобразует программу источника Java, которую мы написали из формата кодирования файла.
Шаг 3: JDK записывает скомпилированную и сохраненную информацию в вышеуказанной памяти в файл класса, чтобы сформировать файл .class. В настоящее время файл .class кодируется Unicode, что означает, что содержимое в наших общих файлах класса преобразуется в формат кодирования Unicode, независимо от того, являются ли они китайскими или английскими символами.
На этом этапе метод обработки исходных файлов JSP немного отличается: веб -контейнер вызывает компилятор JSP. Компилятор JSP сначала проверит, имеет ли файл JSP есть формат кодирования файла. Если он не будет установлен, компилятор JSP вызовет JDK, чтобы преобразовать файл JSP в временный класс сервлета, используя метод кодирования по умолчанию, а затем составить его в файл .class и сохранить его во временной папке.
Шаг 4: Запустите скомпилированный класс: здесь будет несколько ситуаций
(1) Запустите прямо на консоли.
(2) класс JSP/Servlet.
(3) между классом Java и базой данных.
Каждая из этих трех ситуаций будет иметь разные способы сделать это.
1. Занятия, работающие на консоли
В этом случае JVM сначала будет читать файл класса, сохраненный в операционной системе в память. В настоящее время файл класса в памяти кодируется в Unicode, а затем JVM запустит его. Если пользователю необходимо ввести информацию, ввод информации пользователем будет кодирована в формате File.encoding и преобразована в формат кодирования Unicode для сохранения его в памяти. После того, как программа запускается, результат преобразуется в формат file.coding и возвращается в операционную систему и выводит в интерфейс. Весь процесс заключается в следующем:
Во всем вышеприведенном процессе никаких ошибок не может возникнуть ни в каком преобразовании кодирования, в противном случае произойдет искаженная код.
2. Серволет класс
Поскольку файлы JSP в конечном итоге будут преобразованы в файлы сервлета (но место хранилища отличается), мы также будем включать здесь файлы JSP.
Когда пользователь запрашивает сервлет, веб -контейнер вызывает свой JVM для запуска сервлета. Прежде всего, JVM загрузит класс сервлета в память. Код сервлета в памяти находится в формате кодирования Unicode. Затем JVM запускает сервлет в памяти. Во время запуска, если вам нужно принять данные, передаваемые от клиента (например, данные, передаваемые формами и URL), веб -контейнер примет входящие данные. Во время процесса приема, если программа устанавливает кодирование входящих параметров, принят формат кодирования SET. Если он не установлен, принят формат кодирования ISO-8859-1 по умолчанию. После полученных данных JVM будет преобразовать формат кодирования в Unicode и сохранить его в памяти. После запуска сервлета генерируются результаты выходных данных, и формат кодирования этих выходных результатов все еще остается Unicode. Сразу после этого веб -контейнер напрямую отправит сгенерированную строку кодирования кодирования Unicode в клиенту. Если программа указывает формат кодирования во время вывода, она будет выводиться в браузер в соответствии с указанным форматом кодирования. В противном случае принят формат кодирования ISO-8859-1. Вся схема потока процесса выглядит следующим образом:
3. Часть базы данных
Мы знаем, что связь между программами Java и базами данных подключена через драйвер JDBC, а драйвер JDBC по умолчанию в формате кодирования ISO-8859-1. То есть, когда мы передаем данные в базу данных через программу Java, JDBC сначала преобразует данные в формате кодирования Unicode в формат кодирования ISO-8859-1, а затем хранит их в базе данных, то есть, когда база данных сохраняет данные, формат по умолчанию является ISO-8859-1.
2. Кодирование и декодирование
Следующее завершит операции по кодированию и декодированию, которые Java необходимо выполнять в этих случаях, и подробно разобрать промежуточный процесс, чтобы дополнительно освоить процесс кодирования и декодирования Java. В Java есть четыре основных сценария, которые требуют кодирования и декодирования:
(1): операция ввода/вывода
(2): память
(3): база данных
(4): Javaweb
Следующее в основном представляет два предыдущих сценария. Пока детали базы данных устанавливается правильно, проблем не будет. Существует слишком много сценариев Javaweb, и вам необходимо понять кодирование URL, Get, Post и Deplet Decoding, поэтому LZ введение сценария Javaweb.
1. IT/O Операция
В предыдущем LZ упоминается, что искаженная проблема - это не что иное, как несоответствие формата кодирования во время процесса транскодирования. Например, UTF-8 используется для кодирования, а GBK используется для декодирования. Тем не менее, наиболее фундаментальной причиной является то, что существует проблема с преобразованием от символов в байтовые или байтовых в характер, и основным сценарием конверсии в этом случае является операция ввода/вывода. Конечно, операции ввода -вывода в основном включают в себя сетевой ввод -вывод (то есть Javaweb) и диск ввода/вывода. Сетевой ввод -вывод вводится в следующем разделе.
Во -первых, давайте посмотрим на операцию кодирования ввода/вывода.
InputStream - это суперкласс всех классов байтового входного потока, а читатель является абстрактным классом читателя. Java читает файлы таким образом, чтобы разделить на байтовый поток и по потоку символов. InputStream и Reader являются суперклассами этих двух методов чтения.
По байту мы обычно используем метод inputstream.read () для чтения байтов в потоке данных (read () только один байт за раз, что очень медленно. Мы обычно используем чтение (байт [])), затем сохраняем его в массиве байта [] и, наконец, конвертируем его в строку. Когда мы читаем файл, кодирование байтов зависит от формата кодирования, используемого файлом, и задача кодирования также будет участвовать в преобразовании в процесс строки. Если между двумя форматами кодирования различаются, проблема может возникнуть. Например, существует проблема, что формат кодирования test.txt является UTF-8, поэтому формат кодирования потока данных, полученный при чтении файла через байтовый поток, является UTF-8. Если мы не указываем формат кодирования во время преобразования в строку, мы используем формат кодирования системы (GBK) по умолчанию для декодирования. Поскольку форматы кодирования этих двух непоследовательны, тогда искаженный код определенно произойдет в процессе построения строки, следующим образом:
File file = new File ("c: //test.txt"); InputStream input = new FileInputStream (File); StringBuffer Buffer = new StringBuffer (); байт [] байты = новый байт [1024]; for (int n; (n = input.read (bytes))! =-1;) {buffer.append (new String (Bytes, 0, n)); } System.out.println (Buffer); Результат вывода искажен ...
Содержание в test.txt: я CM.
Чтобы избежать искаженного кода, укажите формат кодирования во время процесса строительства строки, чтобы форматы кодирования двух были согласованы во время кодирования и декодирования:
buffer.append (новая строка (байты, 0, n, "UTF-8"));
По характеру, поток символов можно рассматривать как поток обертки. Его базовый слой по -прежнему использует байтовый поток для чтения байтов, а затем он декодирует байты чтения в символы, используя указанный метод кодирования. В Java Reader - это суперкласс, который читает потоки персонажей. Таким образом, с нижней точки зрения, нет никакой разницы между чтением файлов байтами и чтением по характеру. При чтении каждый раз чтение персонажа остается с байтами, а байтовые потоки читают по одному байту за раз.
Конверсия байта и символов Преобразование байтов в символы, по сути, входные сети. API объясняется следующим образом: inputStreamReader - это мост между байтовым потоком к потоку символов: он считывает байты, используя указанный Charset и декодирует их в символы. Набор символов, который он использует, может быть указан или явно задан именем, или он может принять набор символов платформы по умолчанию. Каждый вызов метода read () в InputStreamReader приводит к тому, что один или несколько байтов считываются из базового входного потока. Чтобы обеспечить эффективное преобразование от байта в символ, вы можете прочитать больше байтов из базового потока заранее, превышая байты, необходимые для удовлетворения текущей операции чтения. Объяснение API очень ясное. InputStreamReader по -прежнему использует чтение байтов при чтении файла внизу. После прочтения байтов он должен разобраться в символах в соответствии с указанным форматом кодирования. Если нет указанного формата кодирования, он принимает системный формат кодирования по умолчанию.
String file = "c: //test.txt"; String charset = "utf-8"; // записать символы для конвертации в Byte Stream FileOutputStream outputStream = new FileOutputStream (file); Outputstreamwriter writer = new outputstreamwriter (outputstream, charset); try {writer.write ("I Am Cm"); } наконец {writer.close (); } // Читать байты для конвертации в символы fileInputStream inputStream = new FileInputStream (file); InputStreamReader Reader = New InputStreamReader (inputStream, charset); StringBuffer Buffer = new StringBuffer (); char [] buf = new char [64]; int count = 0; try {while ((count = reader.read (buf))! = -1) {buffer.append (buf, 0, count); }} наконец {reader.close (); } System.out.println (Buffer); 2. Память
Во -первых, давайте посмотрим на следующий простой код
String S = "I Am Cm"; byte [] bytes = s.getbytes (); String S1 = новая строка (байты, "GBK"); String S2 = новая строка (байты);
В этом коде мы видим три процесса преобразования кодирования (один кодирование, два декодирования). Давайте посмотрим на string.gettytes () сначала:
public byte [] getbytes () {return stringcoding.encode (value, 0, value.length); }Внутренне вызовите метод stringCoding.encode ():
статический байт [] encode (char [] ca, int off, int len) {string csn = charset.defaultcharet (). name (); Try {// Используйте вариант charset name encode (), который обеспечивает кэширование. вернуть кодирование (CSN, CA, OFF, Len); } catch (unsupportedencodingexception x) {warnunsupportedcharset (csn); } try {return encode ("iso-8859-1", ca, off, len); } catch (unsupportedencodingexception x) {// Если этот код нажит во время инициализации виртуальной машины, сообщества - это // единственный способ получить какое -либо сообщение об ошибке. Messageutils.err ("iso-8859-1 charset недоступен:" + x.tostring ()); // Если мы не сможем найти ISO-8859-1 (требуемое кодирование), то вещи // серьезно не правы с установкой. System.Exit (1); вернуть ноль; }}Метод Encode (char [] paramarrayofchar, int paramint1, int paramint2) сначала вызывает формат кодирования по умолчанию системы. Если формат кодирования не указан, операция кодирования выполняется по умолчанию с использованием формата кодирования ISO-8859-1. Дальнейшее углубление выглядит следующим образом:
String csn = (charsetname == null)? "ISO-8859-1": charsetName;
В том же методе вы можете видеть, что конструктор новой строки называется методом stringcoding.decode ():
public String (байтовые байты [], int offset, int length, charset charset) {if (charset == null) бросить новое NullpointerException ("charset"); CHACKBOUNDS (байты, смещение, длина); this.value = stringCoding.decode (charset, байты, смещение, длина); } Метод декодирования и обрабатывает формат кодирования одинаково.
Для двух вышеупомянутых ситуаций нам нужно только установить унифицированный формат кодирования, как правило, не будет искаженных проблем.
3. Формат кодирования и кодирования
Сначала посмотрите на диаграмму класса кодирования Java
Сначала установите класс диаграммы в соответствии с указанной диаграммой, затем создайте объект диаграммы в соответствии с диаграммой и, наконец, вызовите charsetencoder.encode, чтобы кодировать строку. Различные типы кодирования будут соответствовать классу, а фактический процесс кодирования завершен в этих классах. На следующей диаграмме времени показана подробный процесс кодирования:
Благодаря этой кодированной классовой диаграмме и диаграмме синхронизации вы можете понять подробный процесс кодирования. Следующее будет кодировать ISO-8859-1, GBK и UTF-8 через простой код.
public class test02 {public static void main (string [] args) бросает UnsupportedEncodingException {String String = "I Am Am CM"; Test02.printThart (string.thararray ()); Test02.printThart (string.getBytes ("iso-8859-1")); Test02.printThart (String.getBytes ("GBK")); Test02.printThart (String.getBytes ("UTF-8")); } / *** Преобразовать char в шестнадцатеричную* / public static void printchart (char [] chars) {for (int i = 0; i <chars.length; i ++) {System.out.print (integer.tohexstring (chars [i])+""); } System.out.println ("" "); } / ** * Byte преобразован в Hex * / public static void printchart (byte [] bytes) {for (int i = 0; i <bytes.length; i ++) {string hex = integer.tohexstring (bytes [i] & 0xff); if (hex.length () == 1) {hex = '0' + hex; } System.out.print (hex.touppercase () + ""); } System.out.println ("" "); }}Выход:
6211 662f 20 63 6d 3f 3f 20 63 6d CE D2 CA C7 20 63 6d E6 88 91 E6 98 AF 20 63 6d
Благодаря программе мы видим, что результат "I Am Cm" является:
char []: 6211 662f 20 63 6d ISO-8859-1: 3F 3F 20 63 6d GBK: CE D2 CA C7 20 63 6D UTF-8: E6 88 91 E6 98 AF 20 63 6D
Картина следующая: