¿Cómo convertir un lector a InputStream y un escritor a OutputStream?

87

¿Existe una forma sencilla de evitar los problemas de codificación de texto?

Andrei Savu
fuente

Respuestas:

45

Realmente no puede evitar lidiar con los problemas de codificación de texto, pero existen soluciones en Apache Commons:

Solo necesita elegir la codificación de su elección.

Pedro
fuente
7
FYI: el código ReaderInputStream tiene un error en la forma en que lee bytes (no funcionará para todas las codificaciones). Prueba: illegalargumentexception.blogspot.com/2009/05/… Hay un error abierto: issues.apache.org/bugzilla/show_bug.cgi?id=40455
McDowell
1
Puede encontrar las clases en la biblioteca commons-io de Apache: commons.apache.org/proper/commons-io
AlikElzin-kilaka
@McDowell, el error que mencionaste está en la implementación de Apache Ant, no en commons-io, por lo que no es relevante para esta respuesta.
Roman
94

Si está comenzando con una cadena, también puede hacer lo siguiente:

new ByteArrayInputStream(inputString.getBytes("UTF-8"))
Ritesh Tendulkar
fuente
7
Una buena ReaderInputStreamimplementación requeriría menos memoria; no debería ser necesario almacenar todos los bytes en una matriz a la vez.
Piotr Findeisen
3
Me gusta esta solución porque funciona cuando necesita un código de prueba unitario que acepta entrada en (por ejemplo) entrada estándar.
Kedar Mhaswade
43

Bueno, un Reader se ocupa de los caracteres y un InputStream se ocupa de los bytes. La codificación especifica cómo desea representar sus caracteres como bytes, por lo que realmente no puede ignorar el problema. En cuanto a evitar problemas, mi opinión es: elija un juego de caracteres (por ejemplo, "UTF-8") y quédese con él.

En cuanto a cómo hacerlo realmente, como se ha señalado, " los nombres obvios para estas clases son ReaderInputStream y WriterOutputStream " . Sorprendentemente, " estos no están incluidos en la biblioteca de Java " aunque las clases 'opuestas', InputStreamReader y OutputStreamWriter son incluido.

Por lo tanto, muchas personas han creado sus propias implementaciones, incluido Apache Commons IO . Dependiendo de los problemas de licencia, probablemente podrá incluir la biblioteca commons-io en su proyecto, o incluso copiar una parte del código fuente (que se puede descargar aquí ).

Como puede ver, la documentación de ambas clases establece que "todas las codificaciones de conjuntos de caracteres admitidas por JRE se manejan correctamente".

NB Un comentario sobre una de las otras respuestas aquí menciona este error . Pero eso afecta a la clase Apache Ant ReaderInputStream ( aquí ), no a la clase Apache Commons IO ReaderInputStream.

Peter Ford
fuente
19

También tenga en cuenta que, si está comenzando con un String, puede omitir la creación de un StringReader y crear un InputStream en un paso usando org.apache.commons.io.IOUtils de Commons IO así:

InputStream myInputStream = IOUtils.toInputStream(reportContents, "UTF-8");

Por supuesto, aún debe pensar en la codificación del texto, pero al menos la conversión se realiza en un solo paso.

Phil Harvey
fuente
4
Este método lo hace básicamente new ByteArrayInputStream(report.toString().getBytes("utf-8")), lo que implica la asignación de dos copias adicionales del informe en la memoria. Si el informe es grande, es malo. Mira mi respuesta.
Oliv
8

Utilizar:

new CharSequenceInputStream(html, StandardCharsets.UTF_8);

De esta forma no se requiere una conversión inicial a Stringy luego abyte[] , lo que asigna mucha más memoria de pila, en caso de que el informe sea grande. Se convierte a bytes sobre la marcha a medida que se lee la secuencia, directamente desde StringBuffer.

Utiliza CharSequenceInputStream del proyecto Apache Commons IO.

Oliv
fuente
5

Los nombres obvios para estas clases son ReaderInputStream y WriterOutputStream. Desafortunadamente, estos no están incluidos en la biblioteca de Java. Sin embargo, Google es tu amigo.

No estoy seguro de que vaya a solucionar todos los problemas de codificación de texto, que son una pesadilla.

Hay un RFE, pero está cerrado, no se solucionará.

Tom Hawtin - tackline
fuente
1
bugs.openjdk.java.net/browse/JDK-4103785 contiene el comentario "tenemos una API pública para la codificación de conjuntos de caracteres ... no hay una razón convincente para agregar estas clases", entonces, ¿cómo se hace esto en Java 7, sin bibliotecas, doce años después?
Piotr Findeisen
5

No puede evitar problemas de codificación de texto, pero Apache commons-io tiene

Tenga en cuenta que estas son las bibliotecas a las que se hace referencia en la respuesta de Peter de koders.com, solo enlaces a la biblioteca en lugar del código fuente.

dfrankow
fuente
4

¿Estás intentando escribir el contenido de un Readera un OutputStream? Si es así, le resultará más fácil ajustar el OutputStreamen an OutputStreamWritery escribir la chars de la Readera la Writer, en lugar de intentar convertir el lector en un InputStream:

final Writer writer = new BufferedWriter(new OutputStreamWriter( urlConnection.getOutputStream(), "UTF-8" ) );
int charsRead;
char[] cbuf = new char[1024];
while ((charsRead = data.read(cbuf)) != -1) {
    writer.write(cbuf, 0, charsRead);
}
writer.flush();
// don't forget to close the writer in a finally {} block
Sam Barnum
fuente
1

Una advertencia al usar WriterOutputStream: no siempre maneja la escritura de datos binarios en un archivo correctamente / igual que un flujo de salida normal. Tuve un problema con esto que me tomó un tiempo localizarlo.

Si puede, le recomiendo usar un flujo de salida como base, y si necesita escribir cadenas, use un contenedor OUtputStreamWriter alrededor del flujo para hacerlo. Es mucho más confiable convertir texto a bytes que al revés, razón por la cual WriterOutputStream no es parte de la biblioteca estándar de Java.

Romeara
fuente
-1

Para leer una cadena en una secuencia usando solo lo que proporciona Java.

InputStream s = new BufferedInputStream( new ReaderInputStream( new StringReader("a string")));
Aaron
fuente
6
ReaderInputStream está en Apache Commons IO.
Will Beason