Codificación de caracteres predeterminada para la salida de consola java

¿Cómo determina Java la encoding utilizada para System.out ?

Dada la siguiente clase:

 import java.io.File; import java.io.PrintWriter; public class Foo { public static void main(String[] args) throws Exception { String s = "xxäñxx"; System.out.println(s); PrintWriter out = new PrintWriter(new File("test.txt"), "UTF-8"); out.println(s); out.close(); } } 

Se guarda como UTF-8 y se comstack con javac -encoding UTF-8 Foo.java en un sistema Windows.

Luego en una consola git-bash (usando el juego de caracteres UTF-8) hago:

 $ java Foo xxõ±xx $ java -Dfile.encoding=UTF-8 Foo xx├ñ├▒xx $ cat test.txt xxäñxx $ java Foo | cat xxäñxx $ java -Dfile.encoding=UTF-8 Foo | cat xxäñxx 

¿Que esta pasando aqui?

Obviamente java comprueba si está conectado a un terminal y está cambiando su encoding en ese caso. ¿Hay alguna manera de forzar a Java a que simplemente genere UTF-8 simple?


Intenté lo mismo con la consola del cmd, también. Redirigir STDOUT no parece hacer ninguna diferencia allí. Sin el parámetro file.encoding, genera la encoding ansi con el parámetro que emite la encoding utf8.

Supongo que su consola aún se ejecuta en cmd.exe. Dudo que tu consola realmente esté esperando UTF-8. Espero que sea realmente una encoding OEM DOS (por ejemplo, 850 o 437 ).

Java codificará los bytes utilizando el conjunto de encoding predeterminado durante la inicialización de JVM.

Reproduciendo en mi PC:

 java Foo 

Java codifica como windows-1252; consola decodifica como IBM850. Resultado: Mojibake

 java -Dfile.encoding=UTF-8 Foo 

Java codifica como UTF-8; consola decodifica como IBM850. Resultado: Mojibake

 cat test.txt 

cat descifra el archivo como UTF-8; cat codifica como IBM850; consola decodifica como IBM850.

 java Foo | cat 

Java codifica como windows-1252; cat decodifica como windows-1252; cat codifica como IBM850; consola decodifica como IBM850

 java -Dfile.encoding=UTF-8 Foo | cat 

Java codifica como UTF-8; gato decodifica como UTF-8; cat codifica como IBM850; consola decodifica como IBM850

Esta implementación de cat debe usar heurística para determinar si los datos de caracteres son UTF-8 o no, luego transcodifica los datos de UTF-8 o ANSI (por ejemplo, windows-1252) a la encoding de la consola (por ejemplo, IBM850).

Esto se puede confirmar con los siguientes comandos:

 $ java HexDump utf8.txt 78 78 c3 a4 c3 b1 78 78 $ cat utf8.txt xxäñxx $ java HexDump ansi.txt 78 78 e4 f1 78 78 $ cat ansi.txt xxäñxx 

El comando cat puede hacer esta determinación porque e4 f1 no es una secuencia UTF-8 válida.

Puede corregir el resultado de Java de la siguiente manera:

  • Establecer la encoding de la consola en el valor ANSI del sistema
  • Usando el tipo de consola
  • Usando una capa de shiv como estás haciendo con el gato

HexDump es una aplicación trivial de Java:

 import java.io.*; class HexDump { public static void main(String[] args) throws IOException { try (InputStream in = new FileInputStream(args[0])) { int r; while((r = in.read()) != -1) { System.out.format("%02x ", 0xFF & r); } System.out.println(); } } }