1. Información general
En este tutorial veremos cómo convertir un InputStream en un String , usando Guava, la biblioteca IO de Apache Commons y Java simple.
Este artículo es parte de la serie "Java - Back to Basic" aquí en Baeldung.
2. Conversión con guayaba
Comencemos con un ejemplo de Guava, aprovechando la funcionalidad ByteSource :
@Test public void givenUsingGuava_whenConvertingAnInputStreamToAString_thenCorrect() throws IOException { String originalString = randomAlphabetic(8); InputStream inputStream = new ByteArrayInputStream(originalString.getBytes()); ByteSource byteSource = new ByteSource() { @Override public InputStream openStream() throws IOException { return inputStream; } }; String text = byteSource.asCharSource(Charsets.UTF_8).read(); assertThat(text, equalTo(originalString)); }
Repasemos los pasos:
- primero , envolvemos nuestro InputStream en ByteSource , y hasta donde yo sé, esta es la forma más fácil de hacerlo
- luego , vemos nuestro ByteSource como un CharSource con un juego de caracteres UTF8.
- finalmente , usamos CharSource para leerlo como una cadena.
Una forma más sencilla de realizar la conversión con Guava , pero la secuencia debe cerrarse explícitamente; afortunadamente, podemos simplemente usar la sintaxis try-with-resources para encargarnos de eso:
@Test public void givenUsingGuavaAndJava7_whenConvertingAnInputStreamToAString_thenCorrect() throws IOException { String originalString = randomAlphabetic(8); InputStream inputStream = new ByteArrayInputStream(originalString.getBytes()); String text = null; try (Reader reader = new InputStreamReader(inputStream)) { text = CharStreams.toString(reader); } assertThat(text, equalTo(originalString)); }
3. Conversión con Apache Commons IO
Veamos ahora cómo hacer esto con la biblioteca Commons IO.
Una advertencia importante aquí es que, a diferencia de Guava, ninguno de estos ejemplos cerrará InputStream , por lo que personalmente prefiero la solución Guava.
@Test public void givenUsingCommonsIo_whenConvertingAnInputStreamToAString_thenCorrect() throws IOException { String originalString = randomAlphabetic(8); InputStream inputStream = new ByteArrayInputStream(originalString.getBytes()); String text = IOUtils.toString(inputStream, StandardCharsets.UTF_8.name()); assertThat(text, equalTo(originalString)); }
También podemos usar StringWriter para hacer la conversión:
@Test public void givenUsingCommonsIoWithCopy_whenConvertingAnInputStreamToAString_thenCorrect() throws IOException { String originalString = randomAlphabetic(8); InputStream inputStream = new ByteArrayInputStream(originalString.getBytes()); StringWriter writer = new StringWriter(); String encoding = StandardCharsets.UTF_8.name(); IOUtils.copy(inputStream, writer, encoding); assertThat(writer.toString(), equalTo(originalString)); }
4. Conversión con Java - InputStream
Veamos ahora un enfoque de nivel inferior usando Java simple: un InputStream y un StringBuilder simple :
@Test public void givenUsingJava5_whenConvertingAnInputStreamToAString_thenCorrect() throws IOException { String originalString = randomAlphabetic(DEFAULT_SIZE); InputStream inputStream = new ByteArrayInputStream(originalString.getBytes()); StringBuilder textBuilder = new StringBuilder(); try (Reader reader = new BufferedReader(new InputStreamReader (inputStream, Charset.forName(StandardCharsets.UTF_8.name())))) { int c = 0; while ((c = reader.read()) != -1) { textBuilder.append((char) c); } } assertEquals(textBuilder.toString(), originalString); }
4.1. Usando Java 8
Java 8 trae un nuevo método lines () al BufferedReader . Veamos cómo podemos utilizarlo para convertir un InputStream en un String:
@Test public void givenUsingJava8_whenConvertingAnInputStreamToAString_thenCorrect() { String originalString = randomAlphabetic(DEFAULT_SIZE); InputStream inputStream = new ByteArrayInputStream(originalString.getBytes()); String text = new BufferedReader( new InputStreamReader(inputStream, StandardCharsets.UTF_8))) .lines() .collect(Collectors.joining("\n")); assertThat(text, equalTo(originalString)); }
Es importante mencionar que lines () usa el método readLine () bajo el capó. readLine () asume que una línea termina con un salto de línea (“\ n”), un retorno de carro (“\ r”) o un retorno de carro seguido inmediatamente por un salto de línea. En otras palabras, es compatible con todos los estilos comunes de final de línea : Unix, Windows e incluso Mac OS antiguo.
Por otro lado, cuando usamos Collectors.joining () , necesitamos decidir explícitamente qué tipo de EOL queremos usar para el String creado .
También podríamos usar Collectors.joining (System.lineSeparator ()) , en cuyo caso la salida depende de la configuración del sistema.
5. Conversión con Java y un escáner
A continuación, veamos un ejemplo simple de Java, utilizando un escáner de texto estándar :
@Test public void givenUsingJava7_whenConvertingAnInputStreamToAString_thenCorrect() throws IOException { String originalString = randomAlphabetic(8); InputStream inputStream = new ByteArrayInputStream(originalString.getBytes()); String text = null; try (Scanner scanner = new Scanner(inputStream, StandardCharsets.UTF_8.name())) { text = scanner.useDelimiter("\\A").next(); } assertThat(text, equalTo(originalString)); }
Tenga en cuenta que InputStream se cerrará con el cierre del escáner .
También vale la pena aclarar qué hace useDelimiter (“\\ A”) . Aquí, pasamos la '\ A', que es una expresión regular de marcador de límite que denota el comienzo de la entrada. Básicamente, esto significa que la llamada next () lee todo el flujo de entrada.
La única razón por la que este es un ejemplo de Java 7, y no uno de Java 5, es el uso de la declaración try-with-resources : convertir eso en un bloque estándar try-finalmente se compilará bien con Java 5 .
6. Conversión mediante ByteArrayOutputStream
Finalmente, veamos otro ejemplo simple de Java, esta vez usando la clase ByteArrayOutputStream :
@Test public void givenUsingPlainJava_whenConvertingAnInputStreamToString_thenCorrect() throws IOException { String originalString = randomAlphabetic(8); InputStream inputStream = new ByteArrayInputStream(originalString.getBytes()); ByteArrayOutputStream buffer = new ByteArrayOutputStream(); int nRead; byte[] data = new byte[1024]; while ((nRead = inputStream.read(data, 0, data.length)) != -1) { buffer.write(data, 0, nRead); } buffer.flush(); byte[] byteArray = buffer.toByteArray(); String text = new String(byteArray, StandardCharsets.UTF_8); assertThat(text, equalTo(originalString)); }
En este ejemplo, primero, InputStream se convierte en ByteArrayOutputStream leyendo y escribiendo bloques de bytes, luego OutputStream se transforma en una matriz de bytes, que se utiliza para crear una cadena .
7. Conversión con java.nio
Otra solución es copiar el contenido de InputStream a un archivo y luego convertirlo en una cadena:
@Test public void givenUsingTempFile_whenConvertingAnInputStreamToAString_thenCorrect() throws IOException { String originalString = randomAlphabetic(DEFAULT_SIZE); InputStream inputStream = new ByteArrayInputStream(originalString.getBytes()); Path tempFile = Files.createTempDirectory("").resolve(UUID.randomUUID().toString() + ".tmp"); Files.copy(inputStream, tempFile, StandardCopyOption.REPLACE_EXISTING); String result = new String(Files.readAllBytes(tempFile)); assertThat(result, equalTo(originalString)); }
Aquí, estamos usando la clase java.nio.file.Files para crear un archivo temporal, además de copiar el contenido de InputStream al archivo. Luego, se usa la misma clase para convertir el contenido del archivo en una cadena con el método readAllBytes () .
8. Conclusión
Después de compilar la mejor manera de hacer la conversión simple, InputStream a String, de una manera correcta y legible, y después de ver tantas respuestas y soluciones tremendamente diferentes, creo que se necesita una mejor práctica clara y concisa para esto .
La implementación de todos estos ejemplos y fragmentos de código se puede encontrar en GitHub : este es un proyecto basado en Maven, por lo que debería ser fácil de importar y ejecutar tal como está.