Constructores de codificación segura
Conseguir que Java le notifique correctamente los errores de codificación es complicado. Debe utilizar el más detallado y, por desgracia, el menos utilizado de los cuatro constructores alternativos para cada uno de InputStreamReader
y OutputStreamWriter
para recibir una excepción adecuada en un error de codificación.
Para la E / S de archivos, asegúrese siempre de usar siempre como segundo argumento para ambos OutputStreamWriter
y InputStreamReader
el elegante argumento del codificador:
Charset.forName("UTF-8").newEncoder()
Hay otras posibilidades aún más elegantes, pero ninguna de las tres posibilidades más simples funciona para el manejo de excepciones. Estos hacen:
OutputStreamWriter char_output = new OutputStreamWriter(
new FileOutputStream("some_output.utf8"),
Charset.forName("UTF-8").newEncoder()
);
InputStreamReader char_input = new InputStreamReader(
new FileInputStream("some_input.utf8"),
Charset.forName("UTF-8").newDecoder()
);
En cuanto a correr con
$ java -Dfile.encoding=utf8 SomeTrulyRemarkablyLongcLassNameGoeShere
El problema es que no utilizará la forma de argumento del codificador completo para los flujos de caracteres, por lo que volverá a perder los problemas de codificación.
Ejemplo más largo
Aquí hay un ejemplo más largo, este que administra un proceso en lugar de un archivo, donde promovemos dos flujos de bytes de entrada diferentes y un flujo de bytes de salida, todos a flujos de caracteres UTF-8 con manejo completo de excepciones :
Process
slave_process = Runtime.getRuntime().exec("perl -CS script args");
OutputStream
__bytes_into_his_stdin = slave_process.getOutputStream();
OutputStreamWriter
chars_into_his_stdin = new OutputStreamWriter(
__bytes_into_his_stdin,
Charset.forName("UTF-8").newEncoder()
);
InputStream
__bytes_from_his_stdout = slave_process.getInputStream();
InputStreamReader
chars_from_his_stdout = new InputStreamReader(
__bytes_from_his_stdout,
Charset.forName("UTF-8").newDecoder()
);
InputStream
__bytes_from_his_stderr = slave_process.getErrorStream();
InputStreamReader
chars_from_his_stderr = new InputStreamReader(
__bytes_from_his_stderr,
Charset.forName("UTF-8").newDecoder()
);
Ahora tiene tres corrientes de carácter que toda excepción aumento en la codificación de errores, llamados respectivamente chars_into_his_stdin
, chars_from_his_stdout
y chars_from_his_stderr
.
Esto es solo un poco más complicado de lo que necesita para su problema, cuya solución di en la primera mitad de esta respuesta. El punto clave es que esta es la única forma de detectar errores de codificación.
No me hagas hablar de PrintStream
las excepciones alimenticias.
InputStreamReader char_input = new InputStreamWriter
debería leer:,InputStreamReader char_input = new InputStreamReader
y elInputStreamReader
constructor toma unCharsetDecoder
, no unCharsetEncoder
.CipherInputStream
, que elimineBadPaddingException
's, incluso si son creados por un flujo de cifrado autenticado :(Deshazte de
FileWriter
yFileReader
, que son inútiles precisamente porque no te permiten especificar la codificación. En su lugar, usenew OutputStreamWriter(new FileOutputStream(file), StandardCharsets.UTF_8)
y
new InputStreamReader(new FileInputStream(file), StandardCharsets.UTF_8);
fuente
Charset.forName("UTF-8").newDecoder()
argumento muy detallado (o alguna construcción más sofisticada) en lugar de solo"UTF-8"
, no se le notificará adecuadamente de los errores de codificación (lea: se suprimirán las excepciones y ocultará misteriosamente los errores de codificación).new OutputStreamWriter(new FileOutputStream(file), StandardCharsets.UTF_8 )
Debe usar la
OutputStreamWriter
clase como parámetro de escritura para suBufferedWriter
. Acepta una codificación. Revise los javadocs para ello.Algo así:
BufferedWriter out = new BufferedWriter(new OutputStreamWriter( new FileOutputStream("jedis.txt"), "UTF-8" ));
O puede establecer la codificación del sistema actual con la propiedad del sistema
file.encoding
en UTF-8.java -Dfile.encoding=UTF-8 com.jediacademy.Runner arg1 arg2 ...
También puede configurarlo como una propiedad del sistema en tiempo de ejecución
System.setProperty(...)
si solo lo necesita para este archivo específico, pero en un caso como este, creo que preferiría elOutputStreamWriter
.Al establecer la propiedad del sistema, puede usar
FileWriter
y esperar que use UTF-8 como la codificación predeterminada para sus archivos. En este caso para todos los archivos que lee y escribe.EDITAR
A partir de API 19, puede reemplazar la cadena "UTF-8" por
StandardCharsets.UTF_8
Como lo sugiere tchrist en los comentarios a continuación , si tiene la intención de detectar errores de codificación en su archivo, se verá obligado a usar el
OutputStreamWriter
enfoque y usar el constructor que recibe un codificador de juego de caracteres.Algo parecido
CharsetEncoder encoder = Charset.forName("UTF-8").newEncoder(); encoder.onMalformedInput(CodingErrorAction.REPORT); encoder.onUnmappableCharacter(CodingErrorAction.REPORT); BufferedWriter out = new BufferedWriter(new OutputStreamWriter(new FileOutputStream("jedis.txt"),encoder));
Puedes elegir entre acciones
IGNORE | REPLACE | REPORT
Además, esta pregunta ya fue respondida aquí .
fuente
InputStreamReader(InputStream in, CharsetDecoder dec)
, de modo que el último argumento seaCharset.forName("UTF-8").newDecoder()
.{In,Out}putStream{Reader,Writer}
constructores diferentes en datos erróneos, descubrirá que tres de ellos enmascaran todas las excepciones que deberían surgir de errores de codificación, y solo la cuarta forma se las entrega correctamente. Ese es el que involucraCharset.forName("UTF-8").newDecoder()
. Explico esto un poco en mi respuesta.Desde Java 11 puedes hacer:
FileWriter fw = new FileWriter("filename.txt", Charset.forName("utf-8"));
fuente
Desde Java 7, existe una manera fácil de manejar la codificación de caracteres de BufferedWriter y BufferedReaders. Puede crear un BufferedWriter directamente utilizando la clase Archivos en lugar de crear varias instancias de Writer. Simplemente puede crear un BufferedWriter, que considera la codificación de caracteres, llamando a:
Puede encontrar más información al respecto en JavaDoc:
fuente
Con texto en chino, intenté usar Charset UTF-16 y afortunadamente funcionó.
¡Espero que esto pueda ayudar!
PrintWriter out = new PrintWriter( file, "UTF-16" );
fuente
OK, es 2019 ahora, y desde Java 11 tienes un constructor con Charset:
fuente
use OutputStream en lugar de FileWriter para establecer el tipo de codificación
// file is your File object where you want to write you data OutputStream outputStream = new FileOutputStream(file); OutputStreamWriter outputStreamWriter = new OutputStreamWriter(outputStream, "UTF-8"); outputStreamWriter.write(json); // json is your data outputStreamWriter.flush(); outputStreamWriter.close();
fuente
en mi opinión
Si desea escribir, siga el tipo UTF-8 . Debe crear una matriz de bytes. Luego, puede hacer lo siguiente:
byte[] by=("<?xml version=\"1.0\" encoding=\"utf-8\"?>"+"Your string".getBytes();
Luego, puede escribir cada byte en el archivo que creó. Ejemplo:
OutputStream f=new FileOutputStream(xmlfile); byte[] by=("<?xml version=\"1.0\" encoding=\"utf-8\"?>"+"Your string".getBytes(); for (int i=0;i<by.length;i++){ byte b=by[i]; f.write(b); } f.close();
fuente