La respuesta obvia es usar, Charset.defaultCharset()
pero recientemente descubrimos que esta podría no ser la respuesta correcta. Me dijeron que el resultado es diferente del conjunto de caracteres predeterminado real utilizado por las clases java.io en varias ocasiones. Parece que Java mantiene 2 juegos de caracteres predeterminados. ¿Alguien tiene alguna idea sobre este tema?
Pudimos reproducir un caso fallido. Es una especie de error del usuario, pero aún puede exponer la causa raíz de todos los demás problemas. Aquí está el código
public class CharSetTest {
public static void main(String[] args) {
System.out.println("Default Charset=" + Charset.defaultCharset());
System.setProperty("file.encoding", "Latin-1");
System.out.println("file.encoding=" + System.getProperty("file.encoding"));
System.out.println("Default Charset=" + Charset.defaultCharset());
System.out.println("Default Charset in Use=" + getDefaultCharSet());
}
private static String getDefaultCharSet() {
OutputStreamWriter writer = new OutputStreamWriter(new ByteArrayOutputStream());
String enc = writer.getEncoding();
return enc;
}
}
Nuestro servidor requiere un juego de caracteres predeterminado en Latin-1 para manejar algunas codificaciones mixtas (ANSI / Latin-1 / UTF-8) en un protocolo heredado. Entonces todos nuestros servidores se ejecutan con este parámetro de JVM,
-Dfile.encoding=ISO-8859-1
Aquí está el resultado en Java 5,
Default Charset=ISO-8859-1
file.encoding=Latin-1
Default Charset=UTF-8
Default Charset in Use=ISO8859_1
Alguien intenta cambiar el tiempo de ejecución de la codificación configurando file.encoding en el código. Todos sabemos que eso no funciona. Sin embargo, esto aparentemente elimina defaultCharset () pero no afecta el juego de caracteres predeterminado real utilizado por OutputStreamWriter.
¿Es esto un error o una característica?
EDITAR: La respuesta aceptada muestra la causa raíz del problema. Básicamente, no puede confiar en defaultCharset () en Java 5, que no es la codificación predeterminada utilizada por las clases de E / S. Parece que Java 6 corrige este problema.
fuente
Respuestas:
Esto es realmente extraño ... Una vez configurado, el conjunto de caracteres predeterminado se almacena en caché y no se cambia mientras la clase está en la memoria. Establecer la
"file.encoding"
propiedad conSystem.setProperty("file.encoding", "Latin-1");
no hace nada. Cada vez queCharset.defaultCharset()
se llama, devuelve el juego de caracteres en caché.Aquí están mis resultados:
Aunque estoy usando JVM 1.6.
(actualizar)
Okay. Reproduje tu error con JVM 1.5.
Mirando el código fuente de 1.5, el juego de caracteres predeterminado en caché no se está configurando. No sé si esto es un error o no, pero 1.6 cambia esta implementación y usa el juego de caracteres en caché:
JVM 1.5:
JVM 1.6:
Cuando configura la codificación del archivo para
file.encoding=Latin-1
la próxima vez que llamaCharset.defaultCharset()
, lo que sucede es que, debido a que el juego de caracteres predeterminado en caché no está configurado, intentará encontrar el juego de caracteres apropiado para el nombreLatin-1
. Este nombre no se encuentra porque es incorrecto y devuelve el predeterminadoUTF-8
.En cuanto a por qué las clases de E / S como
OutputStreamWriter
devuelven un resultado inesperado,la implementación de
sun.nio.cs.StreamEncoder
(que utilizan estas clases de E / S) también es diferente para JVM 1.5 y JVM 1.6. La implementación de JVM 1.6 se basa en elCharset.defaultCharset()
método para obtener la codificación predeterminada, si no se proporciona una a las clases de E / S. La implementación de JVM 1.5 utiliza un método diferenteConverters.getDefaultEncodingName();
para obtener el juego de caracteres predeterminado. Este método utiliza su propia caché del juego de caracteres predeterminado que se establece en la inicialización de JVM:JVM 1.6:
JVM 1.5:
Pero estoy de acuerdo con los comentarios. No deberías confiar en esta propiedad . Es un detalle de implementación.
fuente
Parece un comportamiento indefinido. Sé que, en la práctica, puede cambiar la codificación predeterminada utilizando una propiedad de línea de comandos, pero no creo que lo que sucede cuando lo hace está definido.
ID de error: 4153515 sobre problemas al establecer esta propiedad:
Me estremezco cuando veo que la gente configura la codificación en la línea de comandos; no sabes qué código afectará.
Si no desea utilizar la codificación predeterminada, configure la codificación que desee explícitamente mediante el método / constructor apropiado .
fuente
Primero, Latin-1 es lo mismo que ISO-8859-1, por lo que el valor predeterminado ya estaba bien para usted. ¿Correcto?
Estableció correctamente la codificación en ISO-8859-1 con su parámetro de línea de comando. También lo configura mediante programación en "Latin-1", pero ese no es un valor reconocido de una codificación de archivo para Java. Ver http://java.sun.com/javase/6/docs/technotes/guides/intl/encoding.doc.html
Cuando haces eso, parece que Charset se restablece a UTF-8, al mirar la fuente. Eso al menos explica la mayor parte del comportamiento.
No sé por qué OutputStreamWriter muestra ISO8859_1. Delega a clases sun.misc. * De código cerrado. Supongo que no se trata del todo con la codificación a través del mismo mecanismo, lo cual es extraño.
Pero, por supuesto, siempre debe especificar qué codificación quiere decir en este código. Nunca confiaría en la plataforma predeterminada.
fuente
El comportamiento no es tan extraño. En cuanto a la implementación de las clases, se debe a:
Charset.defaultCharset()
no almacena en caché el conjunto de caracteres determinado en Java 5.Charset.defaultCharset()
volver a invocar provoca una segunda evaluación de la propiedad del sistema, no se encuentra ningún juego de caracteres con el nombre "Latin-1", por lo que el valorCharset.defaultCharset()
predeterminado es "UTF-8".OutputStreamWriter
embargo, está almacenando en caché el juego de caracteres predeterminado y probablemente ya se usa durante la inicialización de la VM, por lo que su juego de caracteres predeterminado se desvíaCharset.defaultCharset()
si la propiedad del sistema "file.encoding" se ha cambiado en tiempo de ejecución.Como ya se señaló, no está documentado cómo debe comportarse la VM en tal situación. La
Charset.defaultCharset()
documentación de la API no es muy precisa sobre cómo se determina el juego de caracteres predeterminado, solo menciona que generalmente se realiza al inicio de la VM, en función de factores como el juego de caracteres predeterminado del sistema operativo o la configuración regional predeterminada.fuente
He configurado el argumento vm en el servidor WAS como -Dfile.encoding = UTF-8 para cambiar el juego de caracteres predeterminado de los servidores.
fuente
cheque
parece ser la misma codificación que la utilizada en la línea de comandos de su sistema.
fuente