2010-03-28 17 views
5

Algunos pseudocódigo:entendimiento codificación de caracteres en Java típica aplicación web

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 

Al guardar el Java String (UTF-16) a Oracle VARCHAR (15) no Oracle también almacena esta como UTF-16? ¿La longitud de un Oracle VARCHAR se refiere al número de caracteres Unicode (y no a la cantidad de bytes)?

Cuando escribimos b en el ServletResponse ¿está escrito como UTF-16 o estamos convirtiendo de manera predeterminada a otra codificación como UTF-8?

Respuesta

4

En lugar de UTF-16, piense en 'representación interna' de su cadena. Una cadena en Java es algún tipo de caracteres, no importa qué codificación se use internamente. La codificación se vuelve relevante, si interactúas con el exterior del programa. En tu ejemplo saveTextInDb, readTextFromDb y escribe eso. Cada vez que intercambia cadenas con el exterior, se utiliza una codificación para la conversión. saveTextInDb (y leer) parecen métodos hechos a sí mismos, al menos yo no los conozco. Entonces, deberías mirar hacia arriba, qué codificación se usa para este método. El método de escritura de un escritor siempre crea bytes, que representan una codificación asociada con el escritor. Si obtiene su Writer de una HttpServletResponse, la codificación asociada es la que se utiliza para generar la respuesta (que se enviará en los encabezados).

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

Este código se devuelve sin un Writer, que traduce las cadenas en codificación UTF-8. Similar si se escribe en un archivo:

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

Si accede a una base de datos, el marco que utilice debe garantizar un intercambio constante de las cadenas con la base de datos.

3

El ServletResponse utilizará ISO 8859-1 (latín 1) de manera predeterminada. UTF-8 es la codificación más común utilizada para las respuestas HTTP que requieren Unicode, pero debe establecer esa codificación específicamente.

Según this document Oracle puede admitir UTF-8 o UTF-16 en la base de datos. Sus métodos que leen/escriben Oracle necesitarán usar la codificación apropiada que coincida con la configuración de la base de datos y traducirla a/desde la representación interna de Java.

4

La capacidad de Oracle para almacenar (y luego recuperar) texto Unicode de la base de datos se basa únicamente en el juego de caracteres de la base de datos (generalmente especificado durante la creación de la base de datos). Se recomienda elegir AL32UTF8 como juego de caracteres para el almacenamiento de texto Unicode en tipos de datos CHAR (incluido VARCHAR/VARCHAR2), ya que le permitirá acceder a todos los puntos de código Unicode sin consumir mucho espacio de almacenamiento en comparación con otras codificaciones como AL16UTF16/AL32UTF32.

Suponiendo que esto se hace, es el controlador JDBC de Oracle el responsable de convertir los datos codificados en UTF-16 en AL32UTF8. Esta conversión "automática" entre codificaciones también ocurre cuando los datos se leen desde la base de datos. Para responder a la consulta sobre la longitud de bytes de VARCHAR, la definición de una columna VARCHAR2 en Oracle implica semántica de bytes - VARCHAR2 (n) se utiliza para definir una columna que puede almacenar n bytes (este es el comportamiento predeterminado, especificado por el parámetro NLS_LENGTH_SEMANTICS de la base de datos); si necesita definir el tamaño en función de los caracteres, se utilizará VARCHAR2 (n CHAR).

La codificación de los datos escritos en el objeto ServletResponse, depende de la codificación de caracteres predeterminada, a menos que esto se especifique mediante las llamadas a la API ServletResponse.setCharacterEncoding() o ServletResponse.setContentType().Con todo, para una solución Unicode completa implica una base de datos Oracle, uno debe tener conocimiento de

  1. La codificación de los datos de entrada (es decir, la codificación de los datos leídos a través del objeto ServletRequest). Esto puede hacerse especificando la codificación aceptada en los formularios HTML a través del accept-charset attribute. Si la codificación es desconocida, la aplicación podría intentar establecerlo en un valor conocido a través del método ServletRequest.setCharacterEncoding(). Este método no cambia la codificación existente de los caracteres en la secuencia. Si el flujo de entrada está en ISO-Latin1, la especificación de una codificación diferente probablemente dará lugar a la emisión de una excepción. El conocimiento de la codificación es importante, ya que las bibliotecas de tiempo de ejecución Java se requieren conocimientos de la codificación original de la corriente, si el contenido de la corriente deben ser tratados como primitivas o cadenas de caracteres. Aparentemente, esto es necesario cuando invoca ServletRequest.getParameter o métodos similares que procesarán la secuencia y devolverán objetos String. El proceso de decodificación dará como resultado la creación de caracteres en la codificación de la plataforma (esto es UTF-16).
  2. La codificación de los datos leídos de los arroyos, en comparación con los datos creados con la JVM. Esto es bastante importante, ya que la codificación de los datos leídos de las transmisiones no puede modificarse. Hay sin embargo, un proceso de decodificación que convertirá caracteres en codificaciones soportadas a UTF-16 caracteres, cada vez que se accede a tales datos como un carácter primitivo o como una cadena. Nuevos objetos String, por otro lado, se pueden crear con una codificación definida. Esto importa cuando se escribe el contenido de la transmisión en otra secuencia (por ejemplo, la secuencia de salida del objeto HttpServletResponse). Si el contenido del flujo de entrada se trata como una secuencia de bytes, y no como caracteres o cadenas, la JVM no realizará ninguna operación de descodificación. Esto implicaría que los bytes escritos en la secuencia de salida no se deben alterar si no se crean los caracteres intermedios o de cadena. De lo contrario, es bastante posible que los contenidos de la secuencia de salida sean mal formados y analizados incorrectamente por un decodificador correspondiente. En palabras más simples,

    • si uno está escribiendo objetos String o caracteres de flujo de salida del servlet, entonces uno debe especificar la codificación que el navegador debe utilizar para decodificar la respuesta. Los codificadores apropiados podrían usarse para codificar la secuencia de caracteres como se especifica en la respuesta deseada.
    • si uno está escribiendo una secuencia de bytes que se interpretarán como caracteres, entonces la codificación que se especifica en la cabecera HTTP deben ser conocidos antes de la mano
    • si uno está escribiendo una secuencia de bytes que se analiza como una secuencia de bytes (para imágenes y otros datos binarios), entonces el concepto de codificación es inmaterial.
  3. El conjunto de caracteres base de datos de la instancia de Oracle. Como se indicó anteriormente, los datos se almacenarán en la base de datos Oracle, en el juego de caracteres definido (para los tipos de datos CHAR). El controlador JDBC de Oracle se encarga de la conversión de datos entre UTF-16 y AL32UTF8 (el carácter de base de datos configurada en este caso) para los tipos de datos CHAR y NCHAR. Cuando invoca resultSet.getString(), el controlador JDBC devuelve una Cadena con caracteres UTF-16. Lo contrario es cierto cuando envía datos a la base de datos también. Si se usa otro conjunto de caracteres base de datos, un nivel adicional de conversión (de la UTF-16 a UTF-8 para el conjunto de caracteres base de datos) se lleva a cabo de forma transparente por el conductor JDBC.
Cuestiones relacionadas