¿Cómo leo / convierto un InputStream en una cadena en Java?


4065

Si tiene un java.io.InputStreamobjeto, ¿cómo debe procesar ese objeto y producir un String?


Supongamos que tengo un archivo InputStreamque contiene datos de texto y quiero convertirlo Stringen un archivo, por ejemplo, puedo escribirlo en un archivo de registro.

¿Cuál es la forma más fácil de tomar InputStreamy convertirlo en a String?

public String convertStreamToString(InputStream is) {
    // ???
}

36
Las respuestas a esta pregunta solo funcionan si desea leer el contenido completo de la transmisión (hasta que se cierre). Como eso no siempre se pretende (las solicitudes http con una conexión de mantenimiento no se cerrarán), este método llama al bloque (no le proporciona el contenido).
f1sh

21
Usted necesita conocer y especificar la codificación de caracteres para la corriente, o si va a tener errores de codificación de caracteres, ya que va a utilizar una codificación elegidos al azar en función de la máquina / instalación / plataforma operativa o versión del mismo, su código se ejecuta en. Es decir, no utilice métodos que dependan de la codificación predeterminada de la plataforma.
Christoffer Hammarström

11
Solo para divertirme con mi propio comentario de hace 9 años, en estos días utilizo "String s = new File (" SomeFile.txt "). Text" de Groovy para leer un archivo completo de una vez y funciona muy bien. Estoy contento de usar Groovy para mi código de no producción (scripting) y, honestamente, forzarlo a lidiar con la codificación y los archivos extremadamente largos como lo hace java es una muy buena idea para el código de producción de todos modos, así que funciona para su propósito, Groovy funciona para scripts rápidos en los que Java no es excelente: solo use la herramienta adecuada para el trabajo y todo funcionará.
Bill K

Simplemente simplificando: ByteArrayOutputStream outputBytes = new ByteArrayOutputStream(); for(byte[] b = new byte[512]; 0 < inputStream.read(b); outputBytes.write(b)); return new String(outputBytes.toByteArray(), StandardCharsets.UTF_8);
Felypp Oliveira

@BillK con Java 11, puede usar lo String s = Files.readString​(Path.of("SomeFile.txt"));que es tan bueno como puede obtener un lenguaje, que nunca admitirá conversiones de tipo mágico como la que describió.
Holger

Respuestas:


2531

Una buena manera de hacer esto es usar los recursos comunes de Apache IOUtils para copiarlos InputStreamen StringWriter... algo así

StringWriter writer = new StringWriter();
IOUtils.copy(inputStream, writer, encoding);
String theString = writer.toString();

o incluso

// NB: does not close inputStream, you'll have to use try-with-resources for that
String theString = IOUtils.toString(inputStream, encoding); 

Alternativamente, podría usarlo ByteArrayOutputStreamsi no desea mezclar sus Streams y Escritores


75
Para los desarrolladores de Android, parece que Android no viene con IOUtils de Apache. Por lo tanto, puede considerar consultar otras respuestas.
Chris.Zou

47
Esta es una pregunta increíblemente antigua en este momento (se hizo en 2008). Merece la pena leer las respuestas más modernas. Algunos usan llamadas nativas de la biblioteca Java 8.
Shadoninja

36
Esta respuesta está muy desactualizada y uno debería poder marcarla como tal (lamentablemente esto no es posible en el cajero automático).
codepleb

77
IOUtils.toString () ha quedado en desuso por mucho tiempo. Esta respuesta definitivamente ya no es la forma recomendada.
Roshan

77
luego edítelo para explicar por qué está en desuso para ayudar a futuros lectores.
Jean-François Fabre

2487

Resuma otras respuestas. Encontré 11 formas principales de hacer esto (ver más abajo). Y escribí algunas pruebas de rendimiento (ver los resultados a continuación):

Formas de convertir un InputStream en una cadena:

  1. Utilizando IOUtils.toString(Apache Utils)

    String result = IOUtils.toString(inputStream, StandardCharsets.UTF_8);
  2. Usando CharStreams(guayaba)

    String result = CharStreams.toString(new InputStreamReader(
          inputStream, Charsets.UTF_8));
    
  3. Usando Scanner(JDK)

    Scanner s = new Scanner(inputStream).useDelimiter("\\A");
    String result = s.hasNext() ? s.next() : "";
    
  4. Usando Stream API (Java 8). Advertencia : esta solución convierte diferentes saltos de línea (como \r\n) a \n.

    String result = new BufferedReader(new InputStreamReader(inputStream))
      .lines().collect(Collectors.joining("\n"));
    
  5. Utilizando la API Stream paralela (Java 8). Advertencia : esta solución convierte diferentes saltos de línea (como \r\n) a \n.

    String result = new BufferedReader(new InputStreamReader(inputStream)).lines()
       .parallel().collect(Collectors.joining("\n"));
    
  6. Usando InputStreamReadery StringBuilder(JDK)

    final int bufferSize = 1024;
    final char[] buffer = new char[bufferSize];
    final StringBuilder out = new StringBuilder();
    Reader in = new InputStreamReader(stream, StandardCharsets.UTF_8);
    int charsRead;
    while((charsRead = in.read(buffer, 0, buffer.length)) > 0) {
        out.append(buffer, 0, charsRead);
    }
    return out.toString();
    
  7. Uso StringWritery IOUtils.copy(Apache Commons)

    StringWriter writer = new StringWriter();
    IOUtils.copy(inputStream, writer, "UTF-8");
    return writer.toString();
    
  8. Usando ByteArrayOutputStreamy inputStream.read(JDK)

    ByteArrayOutputStream result = new ByteArrayOutputStream();
    byte[] buffer = new byte[1024];
    int length;
    while ((length = inputStream.read(buffer)) != -1) {
        result.write(buffer, 0, length);
    }
    // StandardCharsets.UTF_8.name() > JDK 7
    return result.toString("UTF-8");
    
  9. Usando BufferedReader(JDK). Advertencia: esta solución convierte diferentes saltos de línea (como \n\r) a la line.separatorpropiedad del sistema (por ejemplo, en Windows a "\ r \ n").

    String newLine = System.getProperty("line.separator");
    BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream));
    StringBuilder result = new StringBuilder();
    boolean flag = false;
    for (String line; (line = reader.readLine()) != null; ) {
        result.append(flag? newLine: "").append(line);
        flag = true;
    }
    return result.toString();
    
  10. Usando BufferedInputStreamy ByteArrayOutputStream(JDK)

    BufferedInputStream bis = new BufferedInputStream(inputStream);
    ByteArrayOutputStream buf = new ByteArrayOutputStream();
    int result = bis.read();
    while(result != -1) {
        buf.write((byte) result);
        result = bis.read();
    }
    // StandardCharsets.UTF_8.name() > JDK 7
    return buf.toString("UTF-8");
    
  11. Usando inputStream.read()y StringBuilder(JDK). Advertencia : esta solución tiene problemas con Unicode, por ejemplo, con texto en ruso (funciona correctamente solo con texto que no es Unicode)

    int ch;
    StringBuilder sb = new StringBuilder();
    while((ch = inputStream.read()) != -1)
        sb.append((char)ch);
    reset();
    return sb.toString();
    

Advertencia :

  1. Las soluciones 4, 5 y 9 convierten diferentes saltos de línea en uno.

  2. La solución 11 no puede funcionar correctamente con texto Unicode

Pruebas de rendimiento

Pruebas de rendimiento para pequeño String(longitud = 175), url en github (modo = Tiempo promedio, sistema = Linux, puntaje 1,343 es el mejor):

              Benchmark                         Mode  Cnt   Score   Error  Units
 8. ByteArrayOutputStream and read (JDK)        avgt   10   1,343 ± 0,028  us/op
 6. InputStreamReader and StringBuilder (JDK)   avgt   10   6,980 ± 0,404  us/op
10. BufferedInputStream, ByteArrayOutputStream  avgt   10   7,437 ± 0,735  us/op
11. InputStream.read() and StringBuilder (JDK)  avgt   10   8,977 ± 0,328  us/op
 7. StringWriter and IOUtils.copy (Apache)      avgt   10  10,613 ± 0,599  us/op
 1. IOUtils.toString (Apache Utils)             avgt   10  10,605 ± 0,527  us/op
 3. Scanner (JDK)                               avgt   10  12,083 ± 0,293  us/op
 2. CharStreams (guava)                         avgt   10  12,999 ± 0,514  us/op
 4. Stream Api (Java 8)                         avgt   10  15,811 ± 0,605  us/op
 9. BufferedReader (JDK)                        avgt   10  16,038 ± 0,711  us/op
 5. parallel Stream Api (Java 8)                avgt   10  21,544 ± 0,583  us/op

Pruebas de rendimiento para grandes String(longitud = 50100), url en github (modo = Tiempo promedio, sistema = Linux, el puntaje 200,715 es el mejor):

               Benchmark                        Mode  Cnt   Score        Error  Units
 8. ByteArrayOutputStream and read (JDK)        avgt   10   200,715 ±   18,103  us/op
 1. IOUtils.toString (Apache Utils)             avgt   10   300,019 ±    8,751  us/op
 6. InputStreamReader and StringBuilder (JDK)   avgt   10   347,616 ±  130,348  us/op
 7. StringWriter and IOUtils.copy (Apache)      avgt   10   352,791 ±  105,337  us/op
 2. CharStreams (guava)                         avgt   10   420,137 ±   59,877  us/op
 9. BufferedReader (JDK)                        avgt   10   632,028 ±   17,002  us/op
 5. parallel Stream Api (Java 8)                avgt   10   662,999 ±   46,199  us/op
 4. Stream Api (Java 8)                         avgt   10   701,269 ±   82,296  us/op
10. BufferedInputStream, ByteArrayOutputStream  avgt   10   740,837 ±    5,613  us/op
 3. Scanner (JDK)                               avgt   10   751,417 ±   62,026  us/op
11. InputStream.read() and StringBuilder (JDK)  avgt   10  2919,350 ± 1101,942  us/op

Gráficos (pruebas de rendimiento que dependen de la longitud del flujo de entrada en el sistema Windows 7)
ingrese la descripción de la imagen aquí

Prueba de rendimiento (tiempo promedio) dependiendo de la longitud del flujo de entrada en el sistema Windows 7:

 length  182    546     1092    3276    9828    29484   58968

 test8  0.38    0.938   1.868   4.448   13.412  36.459  72.708
 test4  2.362   3.609   5.573   12.769  40.74   81.415  159.864
 test5  3.881   5.075   6.904   14.123  50.258  129.937 166.162
 test9  2.237   3.493   5.422   11.977  45.98   89.336  177.39
 test6  1.261   2.12    4.38    10.698  31.821  86.106  186.636
 test7  1.601   2.391   3.646   8.367   38.196  110.221 211.016
 test1  1.529   2.381   3.527   8.411   40.551  105.16  212.573
 test3  3.035   3.934   8.606   20.858  61.571  118.744 235.428
 test2  3.136   6.238   10.508  33.48   43.532  118.044 239.481
 test10 1.593   4.736   7.527   20.557  59.856  162.907 323.147
 test11 3.913   11.506  23.26   68.644  207.591 600.444 1211.545

17
Mientras escribe la "respuesta resumida", debe tener en cuenta que algunas soluciones convierten automáticamente saltos de línea diferentes (como \r\n) a los \nque en algunos casos podrían no ser deseados. También sería bueno ver la memoria adicional requerida o al menos la presión de asignación (al menos puede ejecutar JMH con -prof gc). Para la publicación realmente genial, sería genial ver los gráficos (dependiendo de la longitud de la cadena dentro del mismo tamaño de entrada y dependiendo del tamaño de entrada dentro de la misma longitud de cadena).
Tagir Valeev

16
Upvoted; Lo más divertido es que los resultados son más de lo esperado: uno debería usar JDK estándar y / o azúcar sintáctica Apache Commons.
Aleksei Matiushkin

25
Publicación increíble Sólo una cosa. Java 8 advierte contra el uso de flujos paralelos en recursos que lo obligarán a bloquear y esperar (como este flujo de entrada) por lo que la opción de flujo paralelo es bastante engorrosa y no vale la pena, ¿no?
mangusbrother

10
¿La corriente paralela realmente mantiene el orden de la línea?
Natix

66
¿ reset()Para qué sirve el ejemplo 11?
Rob Stewart el

2307

Aquí hay una manera de usar solo la biblioteca estándar de Java (tenga en cuenta que la transmisión no está cerrada, su kilometraje puede variar).

static String convertStreamToString(java.io.InputStream is) {
    java.util.Scanner s = new java.util.Scanner(is).useDelimiter("\\A");
    return s.hasNext() ? s.next() : "";
}

Aprendí este truco del artículo "Trucos de Stupid Scanner" . La razón por la que funciona es porque Scanner itera sobre tokens en el flujo, y en este caso separamos los tokens usando el "comienzo del límite de entrada" (\ A), lo que nos da solo un token para todo el contenido del flujo.

Tenga en cuenta que si necesita ser específico sobre la codificación de la secuencia de entrada, puede proporcionar el segundo argumento al Scannerconstructor que indica qué conjunto de caracteres usar (por ejemplo, "UTF-8").

La punta del sombrero también va para Jacob , quien una vez me señaló el artículo mencionado.


8
Gracias, por mi versión de esto, agregué un bloque finalmente que cierra el flujo de entrada, por lo que el usuario no tiene que hacerlo ya que ha terminado de leer la entrada. Simplifica considerablemente el código de la persona que llama.

44
@PavelRepin @Patrick en mi caso, un inputStream vacío causó un NPE durante la construcción del escáner. Tuve que agregar if (is == null) return "";justo al comienzo del método; Creo que esta respuesta debe actualizarse para manejar mejor inputStreams nulos.
CFL_Jeff

115
Para Java 7, puede cerrar en una prueba: try(java.util.Scanner s = new java.util.Scanner(is)) { return s.useDelimiter("\\A").hasNext() ? s.next() : ""; }
earcam

55
Desafortunadamente, esta solución parece ir y perder las excepciones lanzadas en mi implementación de flujo subyacente.
Taig

11
Para su información, tiene bloques siguientes en las secuencias de entrada de la consola (ver aquí ). (Acabo de encontrarme con este problema ahora mismo). De lo contrario, esta solución funciona bien ... solo un aviso.
Ryan

848

Apache Commons permite:

String myString = IOUtils.toString(myInputStream, "UTF-8");

Por supuesto, puede elegir otras codificaciones de caracteres además de UTF-8.

Ver también: ( documentación )


1
Además, hay un método que solo toma un argumento inputStream, si se encuentra con la codificación predeterminada.
Guillaume Coté

13
@Guillaume Coté Supongo que el mensaje aquí es que nunca debe estar "bien con la codificación predeterminada", ya que no puede estar seguro de qué es, dependiendo de la plataforma en la que se ejecuta el código Java.
Según Wiklander

77
@Per Wiklander No estoy de acuerdo contigo. El código que funcionará en un solo podría estar bastante seguro de que la codificación predeterminada estará bien. Para el código que solo abre un archivo local, es una opción razonable pedirles que se codifiquen en la codificación predeterminada de la plataforma.
Guillaume Coté

39
Para salvar a cualquiera la molestia de buscar en Google - <dependency> <groupId> org.apache.commons </groupId> <artifactId> commons-io </artifactId> <version> 1.3.2 </version> </dependency>
Chris

77
También una pequeña mejora sería usar apache io (u otra constante) para la codificación de caracteres en lugar de usar un literal de cadena simple, por ejemplo: IOUtils.toString (myInputStream, Charsets.UTF_8);

300

Teniendo en cuenta el archivo uno, primero debe obtener una java.io.Readerinstancia. Esto se puede leer y agregar a un StringBuilder(no necesitamos StringBuffersi no estamos accediendo a él en múltiples hilos, y StringBuilderes más rápido). El truco aquí es que trabajamos en bloques y, como tal, no necesitamos otras secuencias de almacenamiento en búfer. El tamaño del bloque está parametrizado para la optimización del rendimiento en tiempo de ejecución.

public static String slurp(final InputStream is, final int bufferSize) {
    final char[] buffer = new char[bufferSize];
    final StringBuilder out = new StringBuilder();
    try (Reader in = new InputStreamReader(is, "UTF-8")) {
        for (;;) {
            int rsz = in.read(buffer, 0, buffer.length);
            if (rsz < 0)
                break;
            out.append(buffer, 0, rsz);
        }
    }
    catch (UnsupportedEncodingException ex) {
        /* ... */
    }
    catch (IOException ex) {
        /* ... */
    }
    return out.toString();
}

8
Esta solución utiliza caracteres multibyte. El ejemplo utiliza la codificación UTF-8 que permite la expresión del rango completo Unicode (incluido el chino). Reemplazar "UTF-8" con otra codificación permitiría usar esa codificación.
Paul de Vrieze

27
@ Usuario1: me gusta usar bibliotecas en mi código para poder hacer mi trabajo más rápido. Es increíble cuando tus gerentes dicen "¡Guau James! ¿Cómo hiciste eso tan rápido?". Pero cuando tenemos que dedicar tiempo a reinventar la rueda solo porque hemos perdido las ideas sobre la inclusión de una utilidad común, reutilizable, probada y probada, estamos perdiendo el tiempo que podríamos dedicar a la consecución de los objetivos de nuestro proyecto. Cuando reinventamos la rueda, trabajamos dos veces más duro pero llegamos a la meta mucho más tarde. Una vez que estamos en la línea de meta, no hay nadie allí para felicitarnos. Al construir una casa, no construyas el martillo también
jmort253

10
Lo siento, después de releer mi comentario, resulta un poco arrogante. Simplemente creo que es importante tener una buena razón para evitar las bibliotecas y que la razón es válida, lo que muy bien podría ser :)
jmort253

44
@ jmort253 Notamos una regresión de rendimiento después de actualizar algunas bibliotecas en nuestro producto varias veces. Afortunadamente, estamos construyendo y vendiendo nuestro propio producto, por lo que realmente no tenemos los llamados plazos. Desafortunadamente, estamos creando un producto que está disponible en muchas JVM, bases de datos y servidores de aplicaciones en muchos sistemas operativos, por lo que tenemos que pensar en los usuarios que usan máquinas pobres ... Y una optimización de la operación de cadena puede mejorar el rendimiento en un 30 ~ 40%. Y una solución: In our product, I even replaceddebería ser "incluso reemplazamos".
coolcfan

10
@ jmort253 Si ya usaras apache commons, diría, anímate. Al mismo tiempo, el uso de bibliotecas tiene un costo real (como muestra la proliferación de dependencias en muchas bibliotecas apache java). Si este fuera el único uso de la biblioteca, sería excesivo usar la biblioteca. Por otro lado, al determinar sus propios tamaños de búfer, puede ajustar el saldo de uso de la memoria / procesador.
Paul de Vrieze

248

Utilizar:

InputStream in = /* Your InputStream */;
StringBuilder sb = new StringBuilder();
BufferedReader br = new BufferedReader(new InputStreamReader(in));
String read;

while ((read=br.readLine()) != null) {
    //System.out.println(read);
    sb.append(read);
}

br.close();
return sb.toString();

11
La cuestión es que primero se divide en líneas y luego se deshace. Es más fácil y rápido simplemente leer buffers arbitrarios.
Paul de Vrieze

20
Además, readLine no distingue entre \ n y \ r, por lo que no puede volver a reproducir la secuencia exacta.
María Arias de Reyna Domínguez

2
muy ineficiente, como se readLinelee carácter por carácter para buscar EOL. Además, si no hay un salto de línea en la secuencia, esto realmente no tiene sentido.
njzk2

3
@Gops AB: si prueba esto y su muestra tenía nuevas líneas, verá que la forma en que se construye este bucle usando readline () y StringBuilder.append () no conserva las nuevas líneas.
Russ Bateman el

44
Esta no es la mejor respuesta porque no es estrictamente byte in byte out. El lector mastica las nuevas líneas, por lo que debe tener cuidado para mantenerlas.
Jeffrey Blattman

173

Si está utilizando Google-Collections / Guava, puede hacer lo siguiente:

InputStream stream = ...
String content = CharStreams.toString(new InputStreamReader(stream, Charsets.UTF_8));
Closeables.closeQuietly(stream);

Tenga en cuenta que el segundo parámetro (es decir, Charsets.UTF_8) para el InputStreamReaderno es necesario, pero generalmente es una buena idea especificar la codificación si la conoce (¡lo cual debería!)


2
@harschware: Dada la pregunta: "Si tiene un objeto java.io.InputStream, ¿cómo debe procesar ese objeto y producir una Cadena?" Asumí que una corriente ya está presente en la situación.
Sakuraba

No explicaste muy bien tu respuesta y tenías variables extrañas; user359996 dijo lo mismo que tú, pero mucho más claramente.
Uronym

2
+1 para guayaba, -1 para no especificar la codificación de la secuencia de entrada. p.ej. nuevo InputStreamReader (transmisión, "UTF-8")
andras

@ Chris Noldus Por otro lado, algunas personas ya tienen guayaba en su proyecto, como yo, y piensan que esta solución es más elegante que la versión solo para SDK.
CorayThan

@Vadzim esa respuesta es la misma que esta: ambos usan CharStreams.toString
Tom

125

Esta es la mejor solución Java pura que se adapta perfectamente para Android y cualquier otra JVM.

Esta solución funciona increíblemente bien ... ¡es simple, rápida y funciona en transmisiones pequeñas y grandes de la misma manera! (ver punto de referencia arriba .. No. 8 )

public String readFullyAsString(InputStream inputStream, String encoding)
        throws IOException {
    return readFully(inputStream).toString(encoding);
}

public byte[] readFullyAsBytes(InputStream inputStream)
        throws IOException {
    return readFully(inputStream).toByteArray();
}

private ByteArrayOutputStream readFully(InputStream inputStream)
        throws IOException {
    ByteArrayOutputStream baos = new ByteArrayOutputStream();
    byte[] buffer = new byte[1024];
    int length = 0;
    while ((length = inputStream.read(buffer)) != -1) {
        baos.write(buffer, 0, length);
    }
    return baos;
}

44
Funciona bien en Android en comparación con otras respuestas que funcionan solo en Java empresarial.
vortexwolf

Se bloqueó en Android con el error OutOfMemory en la línea ".write", cada vez, por cadenas cortas.
Adam

He agregado la codificación. solo como nota al margen, el método readFully original que tengo en mi código no devuelve String, devuelve byte [] para una funcionalidad de propósito más general. La implementación de la nueva Cadena (...) con codificación es responsabilidad del usuario que utiliza la API
TacB0sS

2
Nota rápida: la huella de memoria de esto se maximiza 2*n, donde n es el tamaño de la secuencia, según el ByteArrayInputStreamsistema de crecimiento automático.
njzk2

3
Duplica innecesariamente el uso de la memoria, lo cual es valioso en los dispositivos móviles. Será mejor que use InputStreamReader y agregue a StringReader, la conversión de bytes a caracteres se realizará sobre la marcha, no al por mayor al final.
Oliv

84

Para completar, aquí está la solución Java 9 :

public static String toString(InputStream input) throws IOException {
    return new String(input.readAllBytes(), StandardCharsets.UTF_8);
}

El readAllByteses actualmente en el JDK 9 código base principal, por lo que es probable que aparezca en el comunicado. Puede probarlo ahora mismo utilizando las compilaciones de instantáneas JDK 9 .


¿El método no asigna mucha memoria para leer? byte[] buf = new byte[DEFAULT_BUFFER_SIZE];donde lo MAX_BUFFER_SIZE = Integer.MAX_VALUE - 8;que da MAX_BUFFER_SIZE = 2147483639. Google dice que es alrededor de 2.147 GB.
Rekin

Lo siento, cometí un error en los cálculos. Es de 2 GB. He editado el comentario. Entonces, ¿incluso si leo como un archivo de 4kb, uso 2gb de memoria?
Rekin

2
@ChristianHujer, no lo veo en la última confirmación de jdk8u . Los nuevos métodos AFAIK nunca se introducen en las actualizaciones de Java, solo en las versiones principales.
Tagir Valeev

44
@ChristianHujer, la pregunta era sobre InputStream, no sobre Path. Se InputStreampueden crear desde muchas fuentes diferentes, no solo archivos.
Tagir Valeev

55
Esto se escribió hace un año, por lo que para actualizar, confirmo que este método está en el lanzamiento público JDK 9. Además, si su codificación es "ISO-Latin-1", esto será extremadamente eficiente ya que las cadenas Java 9 ahora usan una byte[]implementación si todos los caracteres están en los primeros 256 puntos de código. Esto significa que la nueva cadena (byte [], "ISO-Latin-1") será una simple copia de matriz.
Klitos Kyriacou

66

Utilizar:

import java.io.BufferedInputStream;
import java.io.ByteArrayOutputStream;
import java.io.InputStream;
import java.io.IOException;

public static String readInputStreamAsString(InputStream in)
    throws IOException {

    BufferedInputStream bis = new BufferedInputStream(in);
    ByteArrayOutputStream buf = new ByteArrayOutputStream();
    int result = bis.read();
    while(result != -1) {
      byte b = (byte)result;
      buf.write(b);
      result = bis.read();
    }
    return buf.toString();
}

@ DanielDeLeón No, no lo hace. Es un BufferedInputStream. Las lecturas subyacentes son 8192 bytes a la vez.
Marqués de Lorne

2
@EJP He encontrado que es más lento que usar BufferedInputStream y leer en un búfer de matriz de bytes en lugar de un byte a la vez. Ejemplo: 200 ms frente a 60 ms al leer un archivo MiB 4.56.
jk7

Es extraño que nadie haya señalado el otro problema importante aquí (sí, leer el contenido byte por byte es un desperdicio incluso con el almacenamiento en búfer): se basa en lo que sea la "codificación predeterminada"; esto rara vez es una buena manera. En su lugar, asegúrese de pasar la codificación como argumento a buf.toString().
StaxMan

@ jk7 El tiempo para leer un archivo de 4.56MB es tan pequeño que las diferencias no pueden haber sido significativas.
Marqués de Lorne el

63

Aquí está la solución más elegante y pura de Java (sin biblioteca) que se me ocurrió después de un poco de experimentación:

public static String fromStream(InputStream in) throws IOException
{
    BufferedReader reader = new BufferedReader(new InputStreamReader(in));
    StringBuilder out = new StringBuilder();
    String newLine = System.getProperty("line.separator");
    String line;
    while ((line = reader.readLine()) != null) {
        out.append(line);
        out.append(newLine);
    }
    return out.toString();
}

8
@TorbenKohlmeier, los lectores y los buffers no necesitan estar cerrados. El proporcionado InputStreamdebe ser cerrado por la persona que llama.
Drew Noakes

77
No olvide mencionar que hay un constructor más preferible en InputStreamReader que toma un CharSet.
jontejj

77
¿Por qué la gente sigue usando readLine? si no usa las líneas per se, ¿de qué sirve (excepto ser muy lento?)
njzk2

44
No leer por líneas. ¿Qué pasa si una línea es tan larga que no cabe en el montón?
voho

44
@voho, si una línea es tan larga, entonces no hay forma de asignar el valor de retorno de todos modos, que debe ser igual o mayor en tamaño a esa línea. Si está tratando con archivos tan grandes, debe transmitirlos. Sin embargo, hay muchos casos de uso para cargar pequeños archivos de texto en la memoria.
Drew Noakes

55

Hice un punto de referencia sobre 14 respuestas distintas aquí (perdón por no proporcionar créditos, pero hay demasiados duplicados).

El resultado es muy sorprendente. Resulta que Apache IOUtils es la ByteArrayOutputStreamsolución más lenta y más rápida:

Así que primero aquí está el mejor método:

public String inputStreamToString(InputStream inputStream) throws IOException {
    try(ByteArrayOutputStream result = new ByteArrayOutputStream()) {
        byte[] buffer = new byte[1024];
        int length;
        while ((length = inputStream.read(buffer)) != -1) {
            result.write(buffer, 0, length);
        }

        return result.toString(UTF_8);
    }
}

Resultados de referencia, de 20 MB de bytes aleatorios en 20 ciclos

Tiempo en milisegundos.

  • ByteArrayOutputStreamTest: 194
  • NioStream: 198
  • Java9ISTransferTo: 201
  • Java9ISReadAllBytes: 205
  • BufferedInputStreamVsByteArrayOutputStream: 314
  • ApacheStringWriter2: 574
  • GuavaCharStreams: 589
  • ScannerReaderNoNextTest: 614
  • Lector de escáner: 633
  • ApacheStringWriter: 1544
  • StreamApi: error
  • ParallelStreamApi: error
  • BufferReaderTest: error
  • InputStreamAndStringBuilder: error

Código fuente de referencia

import com.google.common.io.CharStreams;
import org.apache.commons.io.IOUtils;

import java.io.*;
import java.nio.ByteBuffer;
import java.nio.channels.Channels;
import java.nio.channels.ReadableByteChannel;
import java.nio.channels.WritableByteChannel;
import java.util.Arrays;
import java.util.List;
import java.util.Random;
import java.util.stream.Collectors;

/**
 * Created by Ilya Gazman on 2/13/18.
 */
public class InputStreamToString {


    private static final String UTF_8 = "UTF-8";

    public static void main(String... args) {
        log("App started");
        byte[] bytes = new byte[1024 * 1024];
        new Random().nextBytes(bytes);
        log("Stream is ready\n");

        try {
            test(bytes);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    private static void test(byte[] bytes) throws IOException {
        List<Stringify> tests = Arrays.asList(
                new ApacheStringWriter(),
                new ApacheStringWriter2(),
                new NioStream(),
                new ScannerReader(),
                new ScannerReaderNoNextTest(),
                new GuavaCharStreams(),
                new StreamApi(),
                new ParallelStreamApi(),
                new ByteArrayOutputStreamTest(),
                new BufferReaderTest(),
                new BufferedInputStreamVsByteArrayOutputStream(),
                new InputStreamAndStringBuilder(),
                new Java9ISTransferTo(),
                new Java9ISReadAllBytes()
        );

        String solution = new String(bytes, "UTF-8");

        for (Stringify test : tests) {
            try (ByteArrayInputStream inputStream = new ByteArrayInputStream(bytes)) {
                String s = test.inputStreamToString(inputStream);
                if (!s.equals(solution)) {
                    log(test.name() + ": Error");
                    continue;
                }
            }
            long startTime = System.currentTimeMillis();
            for (int i = 0; i < 20; i++) {
                try (ByteArrayInputStream inputStream = new ByteArrayInputStream(bytes)) {
                    test.inputStreamToString(inputStream);
                }
            }
            log(test.name() + ": " + (System.currentTimeMillis() - startTime));
        }
    }

    private static void log(String message) {
        System.out.println(message);
    }

    interface Stringify {
        String inputStreamToString(InputStream inputStream) throws IOException;

        default String name() {
            return this.getClass().getSimpleName();
        }
    }

    static class ApacheStringWriter implements Stringify {

        @Override
        public String inputStreamToString(InputStream inputStream) throws IOException {
            StringWriter writer = new StringWriter();
            IOUtils.copy(inputStream, writer, UTF_8);
            return writer.toString();
        }
    }

    static class ApacheStringWriter2 implements Stringify {

        @Override
        public String inputStreamToString(InputStream inputStream) throws IOException {
            return IOUtils.toString(inputStream, UTF_8);
        }
    }

    static class NioStream implements Stringify {

        @Override
        public String inputStreamToString(InputStream in) throws IOException {
            ReadableByteChannel channel = Channels.newChannel(in);
            ByteBuffer byteBuffer = ByteBuffer.allocate(1024 * 16);
            ByteArrayOutputStream bout = new ByteArrayOutputStream();
            WritableByteChannel outChannel = Channels.newChannel(bout);
            while (channel.read(byteBuffer) > 0 || byteBuffer.position() > 0) {
                byteBuffer.flip();  //make buffer ready for write
                outChannel.write(byteBuffer);
                byteBuffer.compact(); //make buffer ready for reading
            }
            channel.close();
            outChannel.close();
            return bout.toString(UTF_8);
        }
    }

    static class ScannerReader implements Stringify {

        @Override
        public String inputStreamToString(InputStream is) throws IOException {
            java.util.Scanner s = new java.util.Scanner(is).useDelimiter("\\A");
            return s.hasNext() ? s.next() : "";
        }
    }

    static class ScannerReaderNoNextTest implements Stringify {

        @Override
        public String inputStreamToString(InputStream is) throws IOException {
            java.util.Scanner s = new java.util.Scanner(is).useDelimiter("\\A");
            return s.next();
        }
    }

    static class GuavaCharStreams implements Stringify {

        @Override
        public String inputStreamToString(InputStream is) throws IOException {
            return CharStreams.toString(new InputStreamReader(
                    is, UTF_8));
        }
    }

    static class StreamApi implements Stringify {

        @Override
        public String inputStreamToString(InputStream inputStream) throws IOException {
            return new BufferedReader(new InputStreamReader(inputStream))
                    .lines().collect(Collectors.joining("\n"));
        }
    }

    static class ParallelStreamApi implements Stringify {

        @Override
        public String inputStreamToString(InputStream inputStream) throws IOException {
            return new BufferedReader(new InputStreamReader(inputStream)).lines()
                    .parallel().collect(Collectors.joining("\n"));
        }
    }

    static class ByteArrayOutputStreamTest implements Stringify {

        @Override
        public String inputStreamToString(InputStream inputStream) throws IOException {
            try(ByteArrayOutputStream result = new ByteArrayOutputStream()) {
                byte[] buffer = new byte[1024];
                int length;
                while ((length = inputStream.read(buffer)) != -1) {
                    result.write(buffer, 0, length);
                }

                return result.toString(UTF_8);
            }
        }
    }

    static class BufferReaderTest implements Stringify {

        @Override
        public String inputStreamToString(InputStream inputStream) throws IOException {
            String newLine = System.getProperty("line.separator");
            BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream));
            StringBuilder result = new StringBuilder(UTF_8);
            String line;
            boolean flag = false;
            while ((line = reader.readLine()) != null) {
                result.append(flag ? newLine : "").append(line);
                flag = true;
            }
            return result.toString();
        }
    }

    static class BufferedInputStreamVsByteArrayOutputStream implements Stringify {

        @Override
        public String inputStreamToString(InputStream inputStream) throws IOException {
            BufferedInputStream bis = new BufferedInputStream(inputStream);
            ByteArrayOutputStream buf = new ByteArrayOutputStream();
            int result = bis.read();
            while (result != -1) {
                buf.write((byte) result);
                result = bis.read();
            }

            return buf.toString(UTF_8);
        }
    }

    static class InputStreamAndStringBuilder implements Stringify {

        @Override
        public String inputStreamToString(InputStream inputStream) throws IOException {
            int ch;
            StringBuilder sb = new StringBuilder(UTF_8);
            while ((ch = inputStream.read()) != -1)
                sb.append((char) ch);
            return sb.toString();
        }
    }

    static class Java9ISTransferTo implements Stringify {

        @Override
        public String inputStreamToString(InputStream inputStream) throws IOException {
            ByteArrayOutputStream bos = new ByteArrayOutputStream();
            inputStream.transferTo(bos);
            return bos.toString(UTF_8);
        }
    }

    static class Java9ISReadAllBytes implements Stringify {

        @Override
        public String inputStreamToString(InputStream inputStream) throws IOException {
            return new String(inputStream.readAllBytes(), UTF_8);
        }
    }

}

Hacer puntos de referencia en Java no es fácil (especialmente debido a JIT). Después de leer el código fuente de Benchmark, estoy convencido de que esos valores anteriores no son precisos y que todos deben tener cuidado al creerlos.
Dalibor

@Dalibor probablemente debería proporcionar más razonamiento para su reclamo en lugar de solo un enlace.
Ilya Gazman

Creo que es un hecho realmente conocido que no es fácil hacer su propio punto de referencia. Para aquellos que no lo saben, hay un enlace;)
Dalibor

@Dalibor Tal vez no sea el mejor, pero entiendo bien los puntos de referencia de Java, por lo que, a menos que pueda señalar un problema específico, simplemente es engañoso y no continuaré la conversación con usted en esas condiciones.
Ilya Gazman

Principalmente estoy de acuerdo con Dalibor. Dice que tiene una "buena comprensión de los puntos de referencia de Java", pero parece que ha implementado el enfoque más ingenuo mientras aparentemente ignora los problemas bien conocidos de este enfoque. Para empezar, lea cada publicación sobre esta pregunta: stackoverflow.com/questions/504103/…
DavidS

41

Yo usaría algunos trucos de Java 8.

public static String streamToString(final InputStream inputStream) throws Exception {
    // buffering optional
    try
    (
        final BufferedReader br
           = new BufferedReader(new InputStreamReader(inputStream))
    ) {
        // parallel optional
        return br.lines().parallel().collect(Collectors.joining("\n"));
    } catch (final IOException e) {
        throw new RuntimeException(e);
        // whatever.
    }
}

Esencialmente lo mismo que algunas otras respuestas, excepto más sucinto.


55
¿ return nullAlguna vez te llamarían? Se br.lines...arrojan las devoluciones o una excepción.
Holloway

3
@Khaled A Khunaifer: sí, bastante seguro ... tal vez deberías echar un vistazo aquí: docs.oracle.com/javase/tutorial/essential/exceptions/… . Lo que editó erróneamente es una declaración de "prueba con recursos".
jamp

11
¿Por qué llamas parallel()al stream?
robinst

44
Esto no daría como resultado una copia honesta de los datos si la secuencia de origen usara terminaciones de línea de Windows, ya que todo \r\nterminaría convirtiéndose en \n...
Lucas

2
Puede usar System.lineSeparator()para usar el final de línea apropiado dependiente de la plataforma.
Steve K

34

Realicé algunas pruebas de tiempo porque el tiempo siempre importa.

Intenté obtener la respuesta en una cadena de 3 formas diferentes. (se muestra a continuación)
Dejé bloques try / catch para facilitar la lectura.

Para dar contexto, este es el código anterior para los 3 enfoques:

   String response;
   String url = "www.blah.com/path?key=value";
   GetMethod method = new GetMethod(url);
   int status = client.executeMethod(method);

1)

 response = method.getResponseBodyAsString();

2)

InputStream resp = method.getResponseBodyAsStream();
InputStreamReader is=new InputStreamReader(resp);
BufferedReader br=new BufferedReader(is);
String read = null;
StringBuffer sb = new StringBuffer();
while((read = br.readLine()) != null) {
    sb.append(read);
}
response = sb.toString();

3)

InputStream iStream  = method.getResponseBodyAsStream();
StringWriter writer = new StringWriter();
IOUtils.copy(iStream, writer, "UTF-8");
response = writer.toString();

Entonces, después de ejecutar 500 pruebas en cada enfoque con los mismos datos de solicitud / respuesta, aquí están los números. Una vez más, estos son mis hallazgos y sus hallazgos pueden no ser exactamente los mismos, pero escribí esto para dar alguna indicación a otros de las diferencias de eficiencia de estos enfoques.

Rangos:
Enfoque n. ° 1
Enfoque n. ° 3: 2.6% más lento que el n. ° 1
Enfoque n. ° 2: 4.3% más lento que el n. ° 1

Cualquiera de estos enfoques es una solución adecuada para obtener una respuesta y crear una cadena a partir de ella.


2
2) contiene un error, agrega siempre "nulo" al final de la cadena ya que siempre está dando un paso más de lo necesario. El rendimiento será el mismo de todos modos, creo. Esto debería funcionar: String read = null; StringBuffer sb = new StringBuffer (); while ((read = br.readLine ())! = null) {sb.append (read); }
LukeSolar

Cabe señalar que GetMethod es parte de org.apache.commons.httpclient, no Java estándar
jk7

Enfoque # 2 consumirá el '\ n' si el archivo tiene muchas líneas, esta no debería ser la respuesta
Ninja

33

La solución Java pura que utiliza Stream s funciona desde Java 8.

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.stream.Collectors;

// ...
public static String inputStreamToString(InputStream is) throws IOException {
    try (BufferedReader br = new BufferedReader(new InputStreamReader(is))) {
        return br.lines().collect(Collectors.joining(System.lineSeparator()));
    }
}

Como mencionó Christoffer Hammarström debajo de otra respuesta , es más seguro especificar explícitamente el juego de caracteres . Es decir, el constructor InputStreamReader se puede cambiar de la siguiente manera:

new InputStreamReader(is, Charset.forName("UTF-8"))

11
En lugar de hacerlo Charset.forName("UTF-8"), usa StandardCharsets.UTF_8(from java.nio.charset).
robinst

26

Aquí está la respuesta de sampath más o menos, limpiada un poco y representada como una función:

String streamToString(InputStream in) throws IOException {
  StringBuilder out = new StringBuilder();
  BufferedReader br = new BufferedReader(new InputStreamReader(in));
  for(String line = br.readLine(); line != null; line = br.readLine()) 
    out.append(line);
  br.close();
  return out.toString();
}


21

Si no puede usar Commons IO (FileUtils / IOUtils / CopyUtils), aquí hay un ejemplo usando un BufferedReader para leer el archivo línea por línea:

public class StringFromFile {
    public static void main(String[] args) /*throws UnsupportedEncodingException*/ {
        InputStream is = StringFromFile.class.getResourceAsStream("file.txt");
        BufferedReader br = new BufferedReader(new InputStreamReader(is/*, "UTF-8"*/));
        final int CHARS_PER_PAGE = 5000; //counting spaces
        StringBuilder builder = new StringBuilder(CHARS_PER_PAGE);
        try {
            for(String line=br.readLine(); line!=null; line=br.readLine()) {
                builder.append(line);
                builder.append('\n');
            }
        } 
        catch (IOException ignore) { }

        String text = builder.toString();
        System.out.println(text);
    }
}

O si desea velocidad bruta, le propondría una variación de lo que sugirió Paul de Vrieze (que evita usar un StringWriter (que usa un StringBuffer internamente):

public class StringFromFileFast {
    public static void main(String[] args) /*throws UnsupportedEncodingException*/ {
        InputStream is = StringFromFileFast.class.getResourceAsStream("file.txt");
        InputStreamReader input = new InputStreamReader(is/*, "UTF-8"*/);
        final int CHARS_PER_PAGE = 5000; //counting spaces
        final char[] buffer = new char[CHARS_PER_PAGE];
        StringBuilder output = new StringBuilder(CHARS_PER_PAGE);
        try {
            for(int read = input.read(buffer, 0, buffer.length);
                    read != -1;
                    read = input.read(buffer, 0, buffer.length)) {
                output.append(buffer, 0, read);
            }
        } catch (IOException ignore) { }

        String text = output.toString();
        System.out.println(text);
    }
}

Para que su código funcione, tuve que usar this.getClass (). GetClassLoader (). GetResourceAsStream () (usando Eclipse con un proyecto maven)
greuze

19

Este es bueno porque:

  • Maneja con seguridad el juego de caracteres.
  • Usted controla el tamaño del búfer de lectura.
  • Puede aprovisionar la longitud del constructor y no tiene que ser un valor exacto.
  • Está libre de dependencias de la biblioteca.
  • Es para Java 7 o superior.

¿Cómo hacerlo?

public static String convertStreamToString(InputStream is) throws IOException {
   StringBuilder sb = new StringBuilder(2048); // Define a size if you have an idea of it.
   char[] read = new char[128]; // Your buffer size.
   try (InputStreamReader ir = new InputStreamReader(is, StandardCharsets.UTF_8)) {
     for (int i; -1 != (i = ir.read(read)); sb.append(read, 0, i));
   }
   return sb.toString();
}

Para JDK 9

public static String inputStreamString(InputStream inputStream) throws IOException {
    try (inputStream) {
        return new String(inputStream.readAllBytes(), StandardCharsets.UTF_8);
    }
}

1
La catch (Throwable)realidad no debería estar vacío si este es el código de producción.
Christian Hujer

1
¿Qué poner en esta captura - declaración arrojable?
alex

Si bien el uso de UTF-8 suele ser razonable, no debe suponer que los caracteres están codificados de esa manera.
Martin

18

Esta es una respuesta adaptada del org.apache.commons.io.IOUtils código fuente , para aquellos que desean tener la implementación de apache pero no quieren la biblioteca completa.

private static final int BUFFER_SIZE = 4 * 1024;

public static String inputStreamToString(InputStream inputStream, String charsetName)
        throws IOException {
    StringBuilder builder = new StringBuilder();
    InputStreamReader reader = new InputStreamReader(inputStream, charsetName);
    char[] buffer = new char[BUFFER_SIZE];
    int length;
    while ((length = reader.read(buffer)) != -1) {
        builder.append(buffer, 0, length);
    }
    return builder.toString();
}

18

Asegúrese de cerrar las transmisiones al final si usa Stream Readers

private String readStream(InputStream iStream) throws IOException {
    //build a Stream Reader, it can read char by char
    InputStreamReader iStreamReader = new InputStreamReader(iStream);
    //build a buffered Reader, so that i can read whole line at once
    BufferedReader bReader = new BufferedReader(iStreamReader);
    String line = null;
    StringBuilder builder = new StringBuilder();
    while((line = bReader.readLine()) != null) {  //Read till end
        builder.append(line);
        builder.append("\n"); // append new line to preserve lines
    }
    bReader.close();         //close all opened stuff
    iStreamReader.close();
    //iStream.close(); //EDIT: Let the creator of the stream close it!
                       // some readers may auto close the inner stream
    return builder.toString();
}

EDITAR: en JDK 7+, puede usar la construcción de prueba con recursos.

/**
 * Reads the stream into a string
 * @param iStream the input stream
 * @return the string read from the stream
 * @throws IOException when an IO error occurs
 */
private String readStream(InputStream iStream) throws IOException {

    //Buffered reader allows us to read line by line
    try (BufferedReader bReader =
                 new BufferedReader(new InputStreamReader(iStream))){
        StringBuilder builder = new StringBuilder();
        String line;
        while((line = bReader.readLine()) != null) {  //Read till end
            builder.append(line);
            builder.append("\n"); // append new line to preserve lines
        }
        return builder.toString();
    }
}

2
Tiene razón acerca del cierre de transmisiones, sin embargo, la responsabilidad de cerrar transmisiones generalmente recae en el constructor de transmisiones (termine lo que comienza). Por lo tanto, iStreamla persona que llama realmente debería cerrarla porque creó la persona que llama iStream. Además, el cierre de flujos debe hacerse en un finallybloque, o incluso mejor en una declaración de prueba con recursos de Java 7. En su código, cuando readLine()lanza IOExceptiono builder.append()lanza OutOfMemoryError, las transmisiones permanecerían abiertas.
Christian Hujer

16

Otro, para todos los usuarios de Spring:

import java.nio.charset.StandardCharsets;
import org.springframework.util.FileCopyUtils;

public String convertStreamToString(InputStream is) throws IOException { 
    return new String(FileCopyUtils.copyToByteArray(is), StandardCharsets.UTF_8);
}

Los métodos de utilidad en org.springframework.util.StreamUtilsson similares a los de FileCopyUtils, pero dejan la secuencia abierta cuando se hace.


16

Utilice java.io.InputStream.transferTo (OutputStream) compatible con Java 9 y ByteArrayOutputStream.toString (String) que toma el nombre del conjunto de caracteres:

public static String gobble(InputStream in, String charsetName) throws IOException {
    ByteArrayOutputStream bos = new ByteArrayOutputStream();
    in.transferTo(bos);
    return bos.toString(charsetName);
}

¿Qué pasó por nombre de juego de caracteres en su caso?
virsha

1
@virsha Debe determinarlo a partir de la fuente que proporcionó InputStream. Recuerde que no tiene sentido tener una cadena sin saber qué codificación utiliza.
jmehrens

15

Aquí está el método completo para la conversión InputStreamen Stringsin necesidad de utilizar cualquier biblioteca de terceros. Úselo StringBuilderpara un entorno de subproceso único; de lo contrario, úselo StringBuffer.

public static String getString( InputStream is) throws IOException {
    int ch;
    StringBuilder sb = new StringBuilder();
    while((ch = is.read()) != -1)
        sb.append((char)ch);
    return sb.toString();
}

3
En este método no se aplica codificación. Entonces, digamos que los datos recibidos de InputStream están codificados usando UTF-8, la salida será incorrecta. Para solucionar esto, puede usar in = new InputStreamReader(inputStream)y (char)in.read().
Frederic Leitenberger

2
y memoria ineficiente también; Creo que intenté usar esto antes en una entrada grande y StringBuilder se quedó sin memoria
gengkev

1
Hay otra respuesta similar que utiliza un búfer char [] y es más eficiente y se ocupa de charset.
Guillaume Perrot

14

Aquí le mostramos cómo hacerlo utilizando solo el JDK utilizando búferes de matriz de bytes. Así es como IOUtils.copy()funcionan todos los métodos commons-io . Puede reemplazar byte[]con char[]si está copiando desde un en Readerlugar de un InputStream.

import java.io.ByteArrayOutputStream;
import java.io.InputStream;

...

InputStream is = ....
ByteArrayOutputStream baos = new ByteArrayOutputStream(8192);
byte[] buffer = new byte[8192];
int count = 0;
try {
  while ((count = is.read(buffer)) != -1) {
    baos.write(buffer, 0, count);
  }
}
finally {
  try {
    is.close();
  }
  catch (Exception ignore) {
  }
}

String charset = "UTF-8";
String inputStreamAsString = baos.toString(charset);

1
Por favor, describa lo que está tratando de lograr.
Ragunath Jawahar

14

Los usuarios de Kotlin simplemente hacen:

println(InputStreamReader(is).readText())

mientras

readText()

es el método de extensión incorporado de la biblioteca estándar de Kotlin.


En realidad, esto no es del todo correcto porque no cierra la transmisión. Me gustaría recomendar is.bufferedReader().use { it.readText() }.
Max

9

La forma más fácil en JDK es con los siguientes fragmentos de código.

String convertToString(InputStream in){
    String resource = new Scanner(in).useDelimiter("\\Z").next();
    return resource;
}

7

Aquí está mi solución basada en Java 8 , que utiliza la nueva API Stream para recopilar todas las líneas de un InputStream:

public static String toString(InputStream inputStream) {
    BufferedReader reader = new BufferedReader(
        new InputStreamReader(inputStream));
    return reader.lines().collect(Collectors.joining(
        System.getProperty("line.separator")));
}

1
Parece que en realidad no leyó todas las respuestas publicadas antes. La versión de Stream API ya estaba aquí al menos dos veces .
Tagir Valeev

He examinado todas las soluciones, pero no he encontrado ninguna adecuada. Encuentro dos líneas con una breve descripción que se presentan con precisión. El try-catch-block de la otra solución, por ejemplo, nunca se usa. Pero estás en lo correcto. Con tantas respuestas
cambié al

1
No está leyendo el archivo original, está convirtiendo las terminaciones de línea que tenga el archivo en las terminaciones de línea que tiene el sistema operativo, posiblemente cambiando el contenido del archivo.
Christian Hujer

7

En términos de reduce, y concatse puede expresar en Java 8 como:

String fromFile = new BufferedReader(new   
InputStreamReader(inputStream)).lines().reduce(String::concat).get();

1
Será increíblemente lento.
Tagir Valeev

Interesante, ¿por qué? ¿Podrías dar más detalles?
libnull-dev

1
¿No sabes por qué es una mala idea concatenar cadenas en bucle en lugar de usar StringBuilder?
Tagir Valeev

Tienes razón. StringBuilderPodría ser más eficiente. Lo comprobaré, pero mi punto era mostrar un enfoque más funcional con inmutable String.
libnull-dev

Los enfoques funcionales son geniales pero generalmente muy ineficientes.
Lluis Martínez

4

Respuesta de JDK 7/8 que cierra la transmisión y aún arroja una IOException:

StringBuilder build = new StringBuilder();
byte[] buf = new byte[1024];
int length;
try (InputStream is = getInputStream()) {
  while ((length = is.read(buf)) != -1) {
    build.append(new String(buf, 0, length));
  }
}
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.