1. Proceso de conversión de codificación de Java
Siempre usamos un archivo de clase Java para interactuar con los usuarios más directamente (entrada, salida), y el texto contenido en este contenido interactivo puede contener chino. Ya sea que estas clases de Java interactúen con la base de datos o con la página de front-end, su ciclo de vida siempre es así:
(1) Los programadores escriben código de programa a través de un editor en el sistema operativo y guardan el sistema operativo en el formato de .java. Llamamos a estos archivos los archivos de origen.
(2) Compile estos archivos de origen a través de Javac.exe en JDK para formar la clase .class.
(3) Ejecute estas clases directamente o las implementa en un contenedor web para obtener el resultado de la salida.
Estos procesos se observan desde la perspectiva macro, y definitivamente no es posible entender esto. Necesitamos entender realmente cómo se codifica y decodifica Java:
Paso 1: Cuando usamos un editor para escribir un archivo fuente de Java, el archivo del programa utilizará el formato de codificación predeterminado del sistema operativo (generalmente nuestro sistema operativo chino utiliza el formato de codificación GBK) para formar un archivo .java. El archivo de origen Java se guarda en el formato de codificación del archivo. El siguiente código puede ver el valor de parámetro de codificación del sistema.
System.out.println (System.getProperty ("File.Encoding")); Paso 2: Cuando usamos javac.exe para compilar nuestro archivo Java, JDK confirmará primero su codificación de parámetros de compilación para determinar el conjunto de caracteres del código fuente. Si no especificamos el parámetro de compilación, JDK primero obtendrá el archivo de archivo predeterminado del sistema operativo.
Paso 3: JDK escribe la información compilada y guardada en la memoria anterior en el archivo de clase para formar un archivo .class. En este momento, el archivo .class está codificado Unicode, lo que significa que el contenido en nuestros archivos. Clases comunes se convierte en formato de codificación unicode, ya sean caracteres chinos o ingleses.
En este paso, el método de manejo de los archivos de origen JSP es un poco diferente: el contenedor web llama al compilador JSP. El compilador JSP primero verificará si el archivo JSP tiene el formato de codificación del archivo. Si no está configurado, el compilador JSP llamará al JDK para convertir el archivo JSP en una clase de servlet temporal utilizando el método de codificación predeterminado, y luego lo compilará en un archivo .class y manteniéndolo en una carpeta temporal.
Paso 4: Ejecute la clase compilada: habrá varias situaciones aquí
(1) Ejecute directamente en la consola.
(2) Clase JSP/Servlet.
(3) entre la clase Java y la base de datos.
Cada una de estas tres situaciones tendrá diferentes formas de hacerlo.
1. Clases que se ejecutan en la consola
En este caso, el JVM leerá primero el archivo de clase guardado en el sistema operativo en la memoria. En este momento, el archivo de clase en la memoria está codificado en Unicode, y luego el JVM lo ejecutará. Si el usuario necesita ingresar información, la información de información del usuario se codificará en el formato de codificación de archivos y se convertirá en formato de codificación unicode para guardarla en la memoria. Después de ejecutar el programa, el resultado se convierte en File.Coding Format y regresa al sistema operativo y sale a la interfaz. Todo el proceso es el siguiente:
En todo el proceso anterior, no pueden ocurrir errores en ninguna conversión de codificación involucrada, de lo contrario se producirá un código confuso.
2. clase de servicio
Dado que los archivos JSP eventualmente se convertirán en archivos Servlet (pero la ubicación de almacenamiento es diferente), también incluiremos archivos JSP aquí.
Cuando un usuario solicita un servlet, el contenedor web llama a su JVM para ejecutar el servlet. En primer lugar, el JVM cargará la clase Servlet en la memoria. El código de servlet en la memoria está en formato de codificación unicode. Luego, el JVM ejecuta el servlet en la memoria. Durante la ejecución, si necesita aceptar datos aprobados del cliente (como los datos aprobados por formularios y URL), el contenedor web aceptará los datos entrantes. Durante el proceso de recepción, si el programa establece la codificación de los parámetros entrantes, se adopta el formato de codificación establecido. Si no está configurado, se adopta el formato de codificación ISO-8859-1 predeterminado. Después de los datos recibidos, el JVM convertirá el formato de codificación en Unicode y los almacenará en la memoria. Después de ejecutar el servlet, se generan los resultados de la salida y el formato de codificación de estos resultados de salida todavía es unicode. Inmediatamente después, el contenedor web enviará directamente la cadena de formato de codificación unicode generada al cliente. Si el programa especifica el formato de codificación en el momento de la salida, se emitirá al navegador de acuerdo con el formato de codificación especificado. De lo contrario, se adopta el formato de codificación ISO-8859-1 predeterminado. Todo el diagrama de flujo del proceso es el siguiente:
3. Parte de la base de datos
Sabemos que la conexión entre los programas Java y las bases de datos está conectada a través del controlador JDBC, y el controlador JDBC predeterminado al formato de codificación ISO-8859-1. Es decir, cuando pasamos los datos a la base de datos a través del programa Java, JDBC primero convertirá los datos en el formato de codificación de Unicode en el formato de codificación ISO-8859-1, y luego los almacenará en la base de datos, es decir, cuando la base de datos guarda datos, el formato predeterminado es ISO-8859-1.
2. Codificación y decodificación
Lo siguiente finalizará las operaciones de codificación y decodificación que Java necesita realizar en esas ocasiones, y resolverá el proceso intermedio en detalle para dominar aún más el proceso de codificación y decodificación de Java. Hay cuatro escenarios principales en Java que requieren codificación y decodificación:
(1): operación de E/S
(2): memoria
(3): base de datos
(4): Javaweb
El siguiente presenta principalmente los dos escenarios anteriores. Mientras la parte de la base de datos se establezca correctamente, no habrá ningún problema. Hay demasiados escenarios de Javaweb y debe comprender la codificación de URL, obtener, publicar y decodificar servlet, por lo que la introducción LZ del escenario de Javaweb.
1.i/o operación
En el LZ anterior mencionó que el problema confuso no es más que la inconsistencia del formato de codificación durante el proceso de transcodificación. Por ejemplo, UTF-8 se usa para codificar y GBK se usa para decodificar. Sin embargo, la razón más fundamental es que hay un problema con la conversión de carácter a byte o de byte a caracteres, y el escenario principal de conversión en este caso es la operación de E/S. Por supuesto, las operaciones de E/S incluyen principalmente E/S de red (es decir, Javaweb) y E/S de disco. La E/S de red se introduce en la siguiente sección.
Primero, veamos la operación de codificación de E/S.
InputStream es la superclase de todas las clases de la transmisión de entrada de bytes, y el lector es la clase abstracta del lector. Java lee archivos de una manera que se divide en Byte Stream y por transmisión de personajes. InputStream y Reader son las superclase de estos dos métodos de lectura.
Por byte, generalmente usamos el método inputStream.read () para leer bytes en la secuencia de datos (leer () solo lee un byte a la vez, lo cual es muy lento. Usamos Usar lectura (byte [])), luego guardarlo en una matriz de byte [] y finalmente convertirlo en cadena. Cuando leemos un archivo, la codificación de los bytes depende del formato de codificación utilizado por el archivo, y el problema de codificación también estará involucrado en el proceso de conversión a cadena. Si los formatos de codificación son diferentes entre los dos, el problema puede ocurrir. Por ejemplo, hay un problema que el formato de codificación test.txt es UTF-8, por lo que el formato de codificación de flujo de datos obtenido al leer un archivo a través de un flujo de bytes es UTF-8. Si no especificamos el formato de codificación durante la conversión a String, utilizamos el formato de codificación del sistema (GBK) de forma predeterminada para decodificar. Dado que los formatos de codificación de los dos son inconsistentes, el código confuso definitivamente ocurrirá en el proceso de construcción de cadena, de la siguiente manera:
Archivo archivo = nuevo archivo ("c: //test.txt"); InputStream Input = new FileInputStream (archivo); StringBuffer Buffer = new StringBuffer (); byte [] bytes = new Byte [1024]; for (int n; (n = input.read (bytes))! =-1;) {buffer.append (new String (bytes, 0, n)); } System.out.println (buffer); El resultado de la salida está confuso ...
El contenido en Test.txt es: Soy CM.
Para evitar el código confuso, especifique el formato de codificación durante el proceso de construcción de cadenas para que los formatos de codificación de los dos sean consistentes durante la codificación y la decodificación:
buffer.append (nueva cadena (bytes, 0, n, "utf-8"));
Por personaje, la transmisión del personaje puede considerarse como una transmisión de envoltura. Su capa subyacente todavía usa una secuencia de bytes para leer bytes, y luego decodifica los bytes de lectura en caracteres utilizando el método de codificación especificado. En Java, el lector es una superclase que lee transmisiones de personajes. Entonces, desde la perspectiva inferior, no hay diferencia entre leer archivos de bytes y leer por carácter. Al leer, la lectura del personaje se deja con bytes cada vez, y las transmisiones de bytes leen un byte a la vez.
Los bytes de conversión de bytes y caracteres a caracteres son esencialmente InputStreamReader. La API se explica de la siguiente manera: InputStreamReader es el puente entre la secuencia de bytes a la secuencia de caracteres: lee bytes usando el charset especificado y los decodifica en caracteres. El conjunto de caracteres que utiliza se puede especificar o explícitamente por el nombre, o puede aceptar el conjunto de caracteres predeterminado de la plataforma. Cada llamada a un método Read () en el InputStreamReader da como resultado que se lean uno o más bytes de la secuencia de entrada subyacente. Para habilitar una conversión efectiva de byte a carácter, puede leer más bytes del flujo subyacente con anticipación, excediendo los bytes requeridos para satisfacer la operación de lectura actual. La explicación de la API es muy clara. InputStreamReader todavía usa la lectura de bytes al leer el archivo en la parte inferior. Después de leer los bytes, necesita analizar los caracteres de acuerdo con un formato de codificación específico. Si no hay formato de codificación especificado, adopta el formato de codificación predeterminado del sistema.
Archivo de cadena = "c: //test.txt"; String Charset = "UTF-8"; // Escribir caracteres para convertir a Byte Stream FileOutputStream OutputStream = new FileOutputStream (archivo); OutputStreamWriter Writer = new OutputStreamWriter (outputStream, Charset); intente {Writer.Write ("I Am CM"); } Finalmente {Writer.Close (); } // leer bytes para convertir a caracteres fileInputStream inputStream = new FileInputStream (archivo); InputStreamReader Reader = new InputStreamReader (inputStream, Charset); StringBuffer Buffer = new StringBuffer (); char [] buf = nuevo char [64]; int count = 0; Pruebe {while ((count = Reader.read (buf))! = -1) {buffer.append (buf, 0, count); }} Finalmente {Reader.Close (); } System.out.println (buffer); 2. Memoria
Primero, veamos el siguiente código simple
Cadena S = "Soy CM"; byte [] bytes = s.getBytes (); Cadena s1 = nueva cadena (bytes, "gbk"); Cadena s2 = nueva cadena (bytes);
En este código vemos tres procesos de conversión de codificación (uno codificación, dos decodificaciones). Veamos String.gettytes () primero:
public byte [] getBytes () {return stringcoding.encode (value, 0, value.length); }Llame internamente al método StringCoding.Encode ():
byte static [] code (char [] ca, int off, int len) {string csn = charset.defaultcharset (). name (); Pruebe la variante {// use Charset Name code () que proporciona almacenamiento en caché. ENCODE DE RETURN (CSN, CA, OFF, LEN); } Catch (UnsupportedEncodingException x) {warnunsupportedcharset (csn); } try {return encode ("ISO-8859-1", Ca, Off, Len); } Catch (UnsupportedEncodingException x) {// Si este código se presiona durante la inicialización de VM, MessageUtils es // la única forma en que podremos recibir cualquier tipo de mensaje de error. MessageUtils.err ("ISO-8859-1 Charset no disponible:" + X.ToString ()); // Si no podemos encontrar ISO-8859-1 (una codificación requerida), entonces las cosas // están muy mal con la instalación. System.exit (1); regresar nulo; }}El método code (char [] paramArrayOfChar, int paramint1, int paramint2) llama al formato de codificación predeterminado del sistema. Si no se especifica el formato de codificación, la operación de codificación se realiza de forma predeterminada utilizando el formato de codificación ISO-8859-1. La profundización más es la siguiente:
Cadena csn = (charsetName == null)? "ISO-8859-1": CharsetName;
En el mismo método, puede ver que el constructor de una nueva cadena se llama método StringCoding.Decode ():
Public String (byte bytes [], int offset, int longitud, charset charset) {if (charset == null) lanzar nueva nullpointerException ("charset"); checkbounds (bytes, desplazamiento, longitud); this.Value = StringCoding.Decode (charset, bytes, offset, longitud); } El método decodificador y el manejo del formato de codificación de la misma manera.
Para las dos situaciones anteriores, solo necesitamos establecer un formato de codificación unificado, generalmente no habrá problemas confusos.
3. Formato de codificación y codificación
Primero, mira el diagrama de clase de codificación de Java
Primero, establezca la clase de cuadro de cuadro de acuerdo con el gráfico especificado, luego cree el objeto ChartSetEncoder de acuerdo con el cuadro y finalmente llame a CharsetEncoder.encode para codificar la cadena. Diferentes tipos de codificación corresponderán a una clase, y el proceso de codificación real se completa en estas clases. El siguiente diagrama de tiempo muestra el proceso de codificación detallado:
A través de este diagrama de clase codificado y el diagrama de tiempo, puede comprender el proceso de codificación detallado. Lo siguiente codificará ISO-8859-1, GBK y UTF-8 a través de un código simple.
public class test02 {public static void main (string [] args) lanza sin apoyoguredEncodingException {string string = "I am cm"; Test02.printchart (string.toCarArray ()); Test02.printchart (string.getBytes ("ISO-8859-1")); Test02.printchart (string.getBytes ("gbk")); Test02.printchart (string.getBytes ("utf-8")); } / *** Convertir char a hexadecimal* / 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 convertido a 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 (""); }}Producción:
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
A través del programa podemos ver que el resultado de "I Am CM" es:
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
La imagen es la siguiente: