2011-02-07 13 views
8

Esta es mi primera publicación en el desbordamiento de la pila. He estado haciendo Java desde 1998, así que no soy principiante. Recientemente me encontré con un problema de codificación de caracteres de archivo que no recuerdo haber enfrentado alguna vez. Es bastante común tener en cuenta la codificación de caracteres de los archivos de texto y el código de escritura que maneja la codificación correctamente cuando se ejecuta en diferentes plataformas. Pero el problema que encontré fue causado por compilación en una plataforma diferente de la plataforma de ejecución. Eso fue completamente inesperado, porque en mi experiencia cuando javac crea un archivo de clase, los parámetros importantes son los parámetros java source y target, y la versión del JDK que hace la compilación. En mi caso, las clases compiladas con JDK 1.6.0_22 en Mac OS X se comportaron de manera diferente a las compiladas con 1.6.0_23-b05 en Linux, cuando se ejecutaron en Mac OS X. La fuente y el destino especificados fueron 1.4.Problema de codificación del archivo de la plataforma del compilador de Java

Una cadena codificada como ISO-8859_1 en la memoria se escribió en el disco utilizando un método PrintStream println. Según la plataforma en la que se haya COMPILADO el código de Java, la cadena se escribió de forma diferente. Esto condujo a un error. La solución para el error fue especificar la codificación del archivo explícitamente al escribir y leer el archivo.

Lo que me sorprendió fue que el comportamiento difería dependiendo de dónde se compilaron las clases, no de en qué plataforma se ejecutó la clase. Estoy bastante familiarizado con el comportamiento del código de Java de manera diferente cuando se ejecuta en diferentes plataformas. Pero da un poco de miedo cuando el mismo código, compilado en diferentes plataformas, se ejecuta de manera diferente en la misma plataforma.

¿Alguien ha encontrado este problema específico? Parece ser un mal presagio para cualquier código Java que lee y escribe cadenas para archivar sin especificar explícitamente la codificación de caracteres. ¿Y con qué frecuencia se hace eso?

Gracias,

Richard Brewster http://rabbitsoftware.com

+0

fue el archivo problemático codificado como utf-8? ¿Había caracteres problemáticos en la fuente, o los caracteres solo eran inválidos ** después de ** la compilación solo en esa máquina en particular? –

+0

¿Se compiló esto en clases utilizando final estático (compilar final estático "hornea" las cadenas en la clase)? o cuando dice escrito en el disco, ¿está serializando datos? ¿serializar una instancia de clase? Método de serialización que se compila con la codificación predeterminada (es decir, plataforma de compilación)? –

+0

@Steve B .: De hecho, todos los literales de cadena y otras cadenas constantes en tiempo de compilación son "cocidas" en la clase, no solo las estáticas finales. –

Respuesta

4

Me arriesgaría a decir que hay un problema de transcodificación durante la etapa de compilación y el compilador carece de dirección en cuanto a la codificación de un archivo de origen (por ejemplo, véase el interruptor javac -encoding). Los compiladores generalmente usan la codificación predeterminada del sistema si no son específicos, lo que puede dañar los literales de cadena y de caracteres que están dañados (internamente, el bytecode de Java usa un formulario UTF-8 modificado, por lo que los archivos binarios son portátiles). Esta es la única forma en que puedo imaginar que los problemas se presenten en tiempo de compilación.

He escrito un poco acerca de esto here.

7

No hay cosas como una Cadena codificada como ISO-8859-1 en la memoria. Las cadenas de Java en la memoria son siempre cadenas Unicode. (Codificado en UTF-16, pero realmente no necesita ahora esto).

La codificación solo entra en juego cuando ingresas o sacas la cadena; luego, sin una codificación explícita, utiliza el sistema predeterminado (que en algunos sistemas depende de la configuración del usuario).

Como dijo McDowell, la codificación real de su archivo de origen debe coincidir con la codificación que su compilador asume sobre su archivo de origen, de lo contrario, usted obtendrá los problemas que usted observó.Esto se puede conseguir por varios medios:

  • Utilice la opción -encoding del compilador, dando a la codificación del archivo fuente. (Con ant, establezca el parámetro encoding=).
  • Utilice su editor o cualquier otra herramienta (como recode) para cambiar la codificación de su archivo al valor por defecto del compilador.
  • use native2ascii (con la opción -encoding correcta) para traducir su archivo fuente a ASCII con \uXXXX-paisajes.

En el último caso, luego puede compilar este archivo en todas partes con cada codificación predeterminada, por lo que este puede ser el camino a seguir si proporciona el código fuente a las personas que no saben codificar.

Si tiene un proyecto más grande que consta de más de un archivo, todos deben tener la misma codificación, ya que el compilador solo tiene uno de esos conmutadores, no varios.

En todos los proyectos que tuve en los últimos años, siempre codifiqué todos mis archivos en UTF-8, y en mi archivo de compilación establecer el parámetro encoding="utf-8" en la tarea javac. (Mi editor es lo suficientemente inteligente como para reconocer automáticamente la codificación, pero configuré el valor predeterminado para UTF-8.)

La codificación es importante para otras herramientas de manejo de código fuente, como javadoc. (No se debe, además, los -charset y -docencoding opciones para la salida -. Que deben coincidir, pero pueden ser diferentes a la fuente- -encoding)

+0

Esto no tiene que ver con la codificación de origen. No hay literales de cadena involucrados. Se lee una cadena de una conexión de red y luego se escribe en un archivo. Lo que quise decir con 'codificado en memoria como ISO-8859-1' es que la secuencia de entrada se lee usando ese conjunto de caracteres, porque así es como está codificada. –

+0

"sin una codificación explícita, utiliza el sistema predeterminado" Sí, pero el valor predeterminado del sistema de la máquina virtual en tiempo de ejecución, ¿verdad? En este caso, la codificación fue aparentemente determinada por la plataforma de compilación. Un PrintStream se comporta de manera diferente, dependiendo de la plataforma de compilación. Este no es un comportamiento portátil. ¿Ya ves mi punto? –

+0

Creo que necesitamos un ejemplo mínimo para su código. Parece que los dos compiladores de los dos sistemas seleccionaron diferentes métodos. –

1

He tenido problemas similares cuando se utilizan los nombres de variables que no son ASCII (Σ , σ, Δ, etc.) al hacer la fórmula matemática. En Linux, usó codificación UTF-8 durante la interpretación. En Windows se quejó de nombres inválidos porque Windows usa ISO-LATIN-1. La solución fue especificar la codificación en el script ant que utilicé para compilar estos archivos.

+0

Agradable, creo que generalmente las personas escriben 'Sigma' (o' sum'), 'sigma',' delta' y así sucesivamente en lugar de usar las letras griegas correctas. Una vez creé una variable llamada 'ℕ'. Quería llamarlo 'ℕ₀', pero javac no lo aceptó, ya que' ₀' no es un dígito para Java. –

+0

@ Paŭlo Ebermann El problema que tuve fue que había tantas variables y las ecuaciones lo suficientemente complejas como para que la documentación fuera un PITA. Utilicé los caracteres especiales y la documentación/prueba de corrección fue "Ver: skolnik, pp XXX-XXX". El hecho de que la variable fuera la misma que el texto lo hizo mucho más fácil de entender para los demás. – KitsuneYMG

0

Utilice siempre códigos de escape (por ejemplo, \uxxxx) en sus archivos fuente y esto no será un problema. @Paulo mencionó esto, pero quería llamarlo explícitamente.

Cuestiones relacionadas