Come faccio a leggere / convertire un InputStream in una stringa in Java?


4063

Se hai un java.io.InputStreamoggetto, come dovresti elaborarlo e produrre un String?


Supponiamo di avere un file InputStreamcontenente dati di testo e di convertirlo in un file String, quindi ad esempio posso scriverlo in un file di registro.

Qual è il modo più semplice per prendere InputStreame convertirlo in un String?

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

36
Le risposte a questa domanda funzionano solo se si desidera leggere completamente il contenuto dello stream (fino alla sua chiusura). Poiché ciò non è sempre previsto (le richieste HTTP con una connessione keep-alive non verranno chiuse), questi metodi chiamano block (non ti danno il contenuto).
f1sh

21
È necessario conoscere e specificare la codifica dei caratteri per il flusso, oppure si dovrà avere bug di codifica dei caratteri, dal momento che si prevede di utilizzare una codifica scelti a caso a seconda di quale macchina / sistema operativo / piattaforma o la versione di esso il codice viene eseguito su. Cioè, non utilizzare metodi che dipendono dalla codifica predefinita della piattaforma.
Christoffer Hammarström,

11
Solo per divertirmi con il mio commento di 9 anni fa, in questi giorni uso "String s = new File (" SomeFile.txt "). Text" di Groovy per leggere un intero file tutto in una volta e funziona alla grande. Sono contento di usare groovy per il mio codice di non produzione (scripting) e - onestamente forzarti a gestire la codifica e i file estremamente lunghi come java fa è comunque una buona idea per il codice di produzione, quindi funziona per il suo scopo, Groovy funziona per script veloci in cui java non è eccezionale: basta usare lo strumento giusto per il lavoro e tutto funziona.
Bill K,

Semplicemente semplificando: 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 il

@BillK con Java 11, puoi usare ciò String s = Files.readString​(Path.of("SomeFile.txt"));che è buono come una lingua può ottenere, che non supporterà mai conversioni di tipo magico come quella che hai descritto.
Holger,

Risposte:


2530

Un bel modo per farlo è usare Commons Apache IOUtils per copiare il InputStreamin un StringWriter... qualcosa di simile

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

o anche

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

In alternativa, puoi usarlo ByteArrayOutputStreamse non vuoi mescolare i tuoi Stream e Writers


75
Per gli sviluppatori Android, sembra che Android non provenga da IOUtils di Apache. Quindi potresti considerare di riferirti ad altre risposte.
Chris.Zou,

47
Questa è una domanda incredibilmente vecchia a questo punto (è stata posta nel 2008). Vale la pena dedicare del tempo a leggere risposte più moderne. Alcuni usano chiamate native dalla libreria Java 8.
Shadoninja,

36
Questa risposta è fortemente obsoleta e si dovrebbe essere in grado di contrassegnarla come tale (purtroppo questo non è possibile atm).
codepleb

7
IOUtils.toString () è stato a lungo deprecato. Questa risposta sicuramente non è più il modo raccomandato.
Roshan,

7
quindi modificalo per spiegare perché è deprecato per aiutare i futuri lettori.
Jean-François Fabre

2487

Riassumi le altre risposte che ho trovato 11 modi principali per farlo (vedi sotto). E ho scritto alcuni test delle prestazioni (vedere i risultati di seguito):

Modi per convertire un InputStream in una stringa:

  1. Utilizzo di IOUtils.toString(Apache Utils)

    String result = IOUtils.toString(inputStream, StandardCharsets.UTF_8);
  2. Utilizzando CharStreams(Guava)

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

    Scanner s = new Scanner(inputStream).useDelimiter("\\A");
    String result = s.hasNext() ? s.next() : "";
  4. Utilizzo dell'API Stream (Java 8). Avviso : questa soluzione converte diverse interruzioni di riga (come \r\n) in \n.

    String result = new BufferedReader(new InputStreamReader(inputStream))
      .lines().collect(Collectors.joining("\n"));
  5. Utilizzo dell'API Stream parallela (Java 8). Avviso : questa soluzione converte diverse interruzioni di riga (come \r\n) in \n.

    String result = new BufferedReader(new InputStreamReader(inputStream)).lines()
       .parallel().collect(Collectors.joining("\n"));
  6. Utilizzo InputStreamReadere 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. Utilizzo StringWritere IOUtils.copy(Apache Commons)

    StringWriter writer = new StringWriter();
    IOUtils.copy(inputStream, writer, "UTF-8");
    return writer.toString();
  8. Utilizzo ByteArrayOutputStreame 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. Utilizzando BufferedReader(JDK). Avviso: questa soluzione converte diverse interruzioni di riga (come \n\r) in line.separatorproprietà di sistema (ad esempio, in Windows in "\ 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. Utilizzo BufferedInputStreame 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. Utilizzando inputStream.read()e StringBuilder(JDK). Avviso : questa soluzione presenta problemi con Unicode, ad esempio con testo russo (funziona correttamente solo con testo non Unicode)

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

Attenzione :

  1. Le soluzioni 4, 5 e 9 convertono diverse interruzioni di linea in una.

  2. La soluzione 11 non può funzionare correttamente con il testo Unicode

Test delle prestazioni

Test delle prestazioni per piccoli String(lunghezza = 175), url in github (mode = Average Time, system = Linux, il punteggio 1.343 è il migliore):

              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

Test delle prestazioni per big String(lunghezza = 50100), url in github (mode = Average Time, system = Linux, il punteggio 200.715 è il migliore):

               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

Grafici (test delle prestazioni in base alla lunghezza del flusso di input nel sistema Windows 7)
inserisci qui la descrizione dell'immagine

Test delle prestazioni (tempo medio) in base alla lunghezza del flusso di input nel 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
Mentre scrivi la "risposta di riepilogo", dovresti notare che alcune soluzioni convertono automaticamente diverse interruzioni di riga (come \r\n) in \ncui in alcuni casi potrebbero essere indesiderate. Inoltre sarebbe bello vedere la memoria aggiuntiva richiesta o almeno la pressione di allocazione (almeno puoi eseguire JMH con -prof gc). Per un post davvero interessante sarebbe bello vedere i grafici (a seconda della lunghezza della stringa all'interno della stessa dimensione di input e in base alla dimensione dell'input all'interno della stessa lunghezza di stringa).
Tagir Valeev,

16
upvoted; la cosa più divertente è che i risultati sono più del previsto: si dovrebbe usare lo zucchero sintattico JDK standard e / o Apache Commons.
Aleksei Matiushkin,

25
Post fantastico. Solo una cosa. Java 8 mette in guardia dall'uso di flussi paralleli su risorse che ti costringeranno a bloccare e attendere (come questo flusso di input), quindi l'opzione flusso parallelo è piuttosto ingombrante e non ne vale la pena no?
mangusbrother

10
Il flusso parallelo mantiene effettivamente l'ordinamento di linea?
Natix,

6
A cosa serve l' reset()esempio 11?
Rob Stewart,

2307

Ecco un modo usando solo la libreria Java standard (nota che il flusso non è chiuso, il tuo chilometraggio può variare).

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

Ho imparato questo trucco dall'articolo "Stupid Scanner tricks" . Il motivo per cui funziona è perché Scanner scorre i token nello stream e in questo caso separiamo i token usando "inizio del confine di input" (\ A), dandoci così un solo token per l'intero contenuto dello stream.

Nota, se devi essere specifico sulla codifica del flusso di input, puoi fornire il secondo argomento a Scanner costruttore che indica quale set di caratteri usare (es. "UTF-8").

La punta del cappello va anche a Jacob , che una volta mi ha indicato l'articolo detto.


8
Grazie, per la mia versione di questo ho aggiunto un blocco finalmente che chiude il flusso di input, quindi l'utente non deve farlo da quando hai finito di leggere l'input. Semplifica notevolmente il codice chiamante.

4
@PavelRepin @Patrick nel mio caso, un inputStream vuoto ha causato un NPE durante la costruzione dello scanner. Ho dovuto aggiungere if (is == null) return "";proprio all'inizio del metodo; Credo che questa risposta debba essere aggiornata per gestire meglio i flussi di input null.
CFL_Jeff

115
Per Java 7 puoi chiudere in prova: try(java.util.Scanner s = new java.util.Scanner(is)) { return s.useDelimiter("\\A").hasNext() ? s.next() : ""; }
earcam

5
Sfortunatamente questa soluzione sembra andare a perdere le eccezioni generate dalla mia implementazione del flusso sottostante.
Taig,

11
Cordiali saluti, blocchi hasNext sui flussi di input della console (vedere qui ). (Ho appena riscontrato questo problema in questo momento.) Questa soluzione funziona bene altrimenti ... solo un avvertimento.
Ryan,

848

Apache Commons consente:

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

Naturalmente, potresti scegliere altre codifiche di caratteri oltre a UTF-8.

Vedi anche: ( documentazione )


1
Inoltre, esiste un metodo che accetta solo un argomento inputStream, se si trova con la codifica predefinita.
Guillaume Coté,

13
@Guillaume Coté Immagino che il messaggio qui sia che non dovresti mai essere "a posto con la codifica predefinita", dal momento che non puoi essere sicuro di cosa sia, a seconda della piattaforma su cui viene eseguito il codice Java.
Per Wiklander,

7
@Per Wiklander Non sono d'accordo con te. Il codice che funzionerà su un singolo potrebbe essere abbastanza sicuro che la codifica predefinita andrà bene. Per il codice che apre solo il file locale, è un'opzione ragionevole chiedere loro di essere codificati nella codifica predefinita della piattaforma.
Guillaume Coté,

39
Per salvare qualcuno il fastidio di Google - <dipendenza> <groupId> org.apache.commons </groupId> <artifactId> commons-io </artifactId> <version> 1.3.2 </version> </dependency>
Chris

7
Inoltre, un piccolo miglioramento sarebbe l'uso della costante apache io (o di altro tipo) per la codifica dei caratteri invece di usare letterale stringa semplice - ad esempio: IOUtils.toString (myInputStream, Charsets.UTF_8);

300

Tenendo conto del file uno, si dovrebbe prima ottenere java.io.Readerun'istanza. Questo può quindi essere letto e aggiunto a un StringBuilder(non abbiamo bisogno StringBufferse non stiamo accedendo a più thread, ed StringBuilderè più veloce). Il trucco qui è che lavoriamo in blocchi e come tali non abbiamo bisogno di altri flussi di buffering. La dimensione del blocco è parametrizzata per l'ottimizzazione delle prestazioni di runtime.

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
Questa soluzione utilizza caratteri multibyte. L'esempio utilizza la codifica UTF-8 che consente l'espressione dell'intero intervallo Unicode (incluso il cinese). La sostituzione di "UTF-8" con un'altra codifica consentirebbe di utilizzare tale codifica.
Paul de Vrieze,

27
@ Utente1 - Mi piace usare le librerie nel mio codice in modo da poter svolgere il mio lavoro più velocemente. È fantastico quando i tuoi manager dicono "Wow James! Come hai fatto a farlo così in fretta ?!". Ma quando dobbiamo dedicare del tempo a reinventare la ruota solo perché abbiamo idee sbagliate sull'inclusione di un'utilità comune, riutilizzabile, provata e testata, stiamo perdendo tempo e potremmo spendere per promuovere gli obiettivi del nostro progetto. Quando reinventiamo la ruota, lavoriamo due volte più duramente, ma arriviamo al traguardo molto più tardi. Una volta arrivati ​​al traguardo, non c'è più nessuno a congratularsi con noi. Quando costruisci una casa, non costruire anche il martello
jmort253

10
Scusa, dopo aver riletto il mio commento, viene fuori un po 'arrogante. Penso solo che sia importante avere una buona ragione per evitare le biblioteche e che la ragione sia valida, cosa che potrebbe benissimo essere :)
jmort253

4
@ jmort253 Abbiamo notato una regressione delle prestazioni dopo aver aggiornato alcune librerie nel nostro prodotto per diverse volte. Fortunatamente stiamo costruendo e vendendo il nostro prodotto, quindi non abbiamo davvero le cosiddette scadenze. Sfortunatamente stiamo costruendo un prodotto che è disponibile su molte JVM, database e server di app su molti sistemi operativi, quindi dobbiamo pensare agli utenti che usano macchine scadenti ... E l'ottimizzazione dell'operazione di stringa può migliorare il perf del 30 ~ 40%. E una soluzione: In our product, I even replaceddovrebbe essere "abbiamo persino sostituito".
coolcfan,

10
@ jmort253 Se dovessi già usare Apache Commons, direi, provaci. Allo stesso tempo, l'utilizzo delle librerie comporta un costo reale (come mostra la proliferazione delle dipendenze in molte librerie Java di Apache). Se questo fosse l'unico uso della libreria, sarebbe eccessivo utilizzare la libreria. D'altra parte, determinando le proprie dimensioni del buffer è possibile ottimizzare il saldo di utilizzo della memoria / del processore.
Paul de Vrieze,

248

Uso:

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
Il fatto è che prima ti dividi in linee e poi lo annulli. È più semplice e veloce leggere solo buffer arbitrari.
Paul de Vrieze,

20
Inoltre, readLine non distingue tra \ n e \ r, quindi non è possibile riprodurre nuovamente il flusso esatto.
María Arias de Reyna Domínguez,

2
molto inefficiente, come readLineletto carattere per carattere per cercare EOL. Inoltre, se non c'è interruzione di linea nello stream, questo non ha davvero senso.
njzk2,

3
@Gops AB: se lo provi e il tuo campione conteneva delle nuove righe, vedrai che il modo in cui questo ciclo è costruito usando readline () e StringBuilder.append () in realtà non preserva le nuove righe.
Russ Bateman,

4
Questa non è la risposta migliore perché non è strettamente byte in byte out. Il lettore scrive nuove righe, quindi devi stare attento a mantenerle.
Jeffrey Blattman,

173

Se si utilizza Google-Collections / Guava è possibile effettuare le seguenti operazioni:

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

Nota che il secondo parametro (es. Charsets.UTF_8) per il InputStreamReadernon è necessario, ma è generalmente una buona idea specificare la codifica se la conosci (cosa che dovresti!)


2
@harschware: data la domanda era: "Se hai un oggetto java.io.InputStream come dovresti elaborare quell'oggetto e produrre una stringa?" Ho pensato che un flusso fosse già presente nella situazione.
Sakuraba,

Non hai spiegato molto bene la tua risposta e avevi variabili estranee; user359996 ha detto la stessa cosa di te, ma molto più chiaramente.
Uronym,

2
+1 per guava, -1 per non aver specificato la codifica del flusso di input. per esempio. nuovo InputStreamReader (stream, "UTF-8")
andras

@Chris Noldus D'altra parte, alcune persone hanno già la guava nel loro progetto, come me, e pensano che questa soluzione sia più elegante della versione solo per sdk.
Coray:

@Vadzim quella risposta è la stessa di questa - entrambi usano CharStreams.toString
Tom

125

Questa è la migliore soluzione Java pura che si adatta perfettamente per Android e qualsiasi altra JVM.

Questa soluzione funziona incredibilmente bene ... è semplice, veloce e funziona su flussi piccoli e grandi allo stesso modo !! (vedi punto di riferimento sopra .. N. 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;
}

4
Funziona bene su Android rispetto ad altre risposte che funzionano solo in Java Enterprise.
vortexwolf

Si è bloccato in Android con errore OutOfMemory sulla riga ".write", ogni volta, per stringhe brevi.
Adam,

Ho aggiunto la codifica. come nota a margine, il metodo readFully originale che ho nel mio codice non restituisce String, ma restituisce byte [] per una funzionalità più generica. L'implementazione della nuova stringa (...) con la codifica è responsabilità dell'on che utilizza l'API!
TacB0sS

2
Nota rapida: il footprint di memoria di questo è massimo 2*n, dove n è la dimensione del flusso, secondo il ByteArrayInputStreamsistema di crescita automatica.
njzk2,

3
Raddoppia inutilmente l'utilizzo della memoria, il che è prezioso sui dispositivi mobili. Faresti meglio a utilizzare InputStreamReader e aggiungere a StringReader, la conversione da byte a char verrà eseguita al volo, non in blocco alla fine.
Oliv

84

Per completezza ecco la soluzione Java 9 :

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

Il file readAllBytesè attualmente nella base di codice principale di JDK 9, quindi è probabile che appaia nella versione. Puoi provarlo ora usando le build di snapshot JDK 9 .


Il metodo non alloca molta memoria per la lettura? byte[] buf = new byte[DEFAULT_BUFFER_SIZE];dove MAX_BUFFER_SIZE = Integer.MAX_VALUE - 8;che dà MAX_BUFFER_SIZE = 2147483639. Google dice che sono circa 2.147 GB.
Rekin,

Spiacenti, ho fatto un errore nei calcoli. Sono 2 GB. Ho modificato il commento. Quindi, anche se leggo come un file da 4kb, utilizzo 2 GB di memoria?
Rekin,

2
@ChristianHujer, non lo vedo nell'ultimo commit di jdk8u . I nuovi metodi AFAIK non vengono mai introdotti negli aggiornamenti Java, ma solo nelle versioni principali.
Tagir Valeev,

4
@ChristianHujer, la domanda riguardava InputStream, non circa Path. Il InputStreampossono essere creati da molte fonti diverse, non solo i file.
Tagir Valeev,

5
Questo è stato scritto un anno fa, quindi per aggiornare, confermo che questo metodo è effettivamente nella versione pubblica JDK 9. Inoltre, se la tua codifica è "ISO-Latin-1", questo sarà estremamente efficiente poiché Java 9 Strings ora utilizza byte[]un'implementazione se tutti i caratteri sono nei primi 256 punti codice. Ciò significa che la nuova stringa (byte [], "ISO-Latin-1") sarà una semplice copia dell'array.
Klitos Kyriacou,

66

Uso:

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, non lo è. È un BufferedInputStream. Le letture sottostanti sono 8192 byte alla volta.
Marchese di Lorne,

2
@EJP L'ho trovato più lento rispetto all'uso BufferedInputStream e alla lettura in un buffer di array di byte anziché in un byte alla volta. Esempio: 200 ms contro 60 ms durante la lettura di un file MiB 4,56.
jk7

Strano che nessuno abbia segnalato l'altro grosso problema qui (sì, leggere il contenuto byte per byte è dispendioso anche con il buffering): si basa su qualunque sia la "codifica predefinita" - raramente è un buon metodo. Assicurati invece di passare la codifica come argomento a buf.toString().
StaxMan

@ jk7 Il tempo di leggere un file di 4,56 MB è così piccolo che le differenze non possono essere state significative.
Marchese di Lorne,

63

Ecco la soluzione più elegante, pura di Java (senza libreria) che ho trovato dopo un po 'di sperimentazione:

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, i lettori e i buffer non devono essere chiusi. Il fornito InputStreamdeve essere chiuso dal chiamante.
Drew Noakes,

7
Non dimenticare di menzionare che c'è un costruttore più preferibile in InputStreamReader che accetta un CharSet.
jontejj,

7
perché le persone continuano a usare readLine? se non usi le linee di per sé, a cosa serve (tranne che essere molto lento?)
njzk2

4
Non leggere per righe. Cosa succede se una riga è così lunga da non adattarsi all'heap?
Voho,

4
@voho, se una riga è così lunga, non c'è modo di allocare comunque il valore di ritorno che deve essere uguale o maggiore in dimensione a quella riga. Se hai a che fare con file così grandi, dovresti trasmetterli in streaming. Tuttavia, ci sono molti casi d'uso per caricare piccoli file di testo in memoria.
Drew Noakes,

55

Ho fatto un benchmark su 14 risposte distinte qui (scusate per non aver fornito crediti ma ci sono troppi duplicati).

Il risultato è molto sorprendente. Si scopre che Apache IOUtils è il più lento eByteArrayOutputStream è la più veloce:

Quindi prima ecco il metodo migliore:

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);
    }
}

Risultati benchmark, di 20 MB di byte casuali in 20 cicli

Tempo in millisecondi

  • ByteArrayOutputStreamTest: 194
  • NioStream: 198
  • Java9ISTransfer A: 201
  • Java9ISReadAllBytes: 205
  • BufferedInputStreamVsByteArrayOutputStream: 314
  • ApacheStringWriter2: 574
  • Stream di GuavaChar: 589
  • ScannerReaderNoNextTest: 614
  • ScannerReader: 633
  • ApacheStringWriter: 1544
  • StreamApi: errore
  • ParallelStreamApi: errore
  • BufferReaderTest: errore
  • InputStreamAndStringBuilder: errore

Codice sorgente benchmark

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);
        }
    }

}

Fare benchmark in Java non è facile (soprattutto a causa di JIT). Dopo aver letto il codice sorgente del benchmark, sono convinto che quei valori sopra non siano precisi e tutti dovrebbero stare attenti credendoli.
Dalibor,

@Dalibor probabilmente dovresti fornire più ragionamenti per il tuo reclamo piuttosto che solo un link.
Ilya Gazman,

Penso che sia noto che non è facile creare il tuo benchmark. Per coloro che non lo sanno, esiste un collegamento;)
Dalibor,

@Dalibor Forse non sono il migliore, ma ho una buona conoscenza dei benchmark Java, quindi a meno che tu non possa evidenziare un problema specifico, sei solo fuorviante e non continuerò la conversazione con te in quelle condizioni.
Ilya Gazman,

Principalmente concordo con Dalibor. Dici di avere una "buona conoscenza dei benchmark Java", ma sembra che tu abbia implementato l'approccio più ingenuo pur essendo apparentemente ignaro dei problemi ben noti di questo approccio. Per cominciare, leggere tutti i post su questo argomento: stackoverflow.com/questions/504103/...
Davids

41

Vorrei usare alcuni trucchi 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.
    }
}

Sostanzialmente uguale ad alcune altre risposte tranne quelle più succinte.


5
Sarebbe return nullmai stato chiamato? Vengono br.lines...restituiti i ritorni o un'eccezione.
Holloway,

3
@Khaled A Khunaifer: sì, abbastanza sicuro ... forse dovresti dare un'occhiata qui: docs.oracle.com/javase/tutorial/essential/exceptions/… . Ciò che hai erroneamente modificato è un'istruzione "prova con risorse".
Jamp

11
Perché chiami parallel()in streaming?
robinst,

4
Ciò non si tradurrebbe in una copia onesta dei dati se il flusso di origine usasse le terminazioni di linea di Windows poiché tutto \r\nfinirebbe per essere convertito in \n...
Lucas

2
È possibile utilizzare System.lineSeparator()per utilizzare il finale di linea appropriato dipendente dalla piattaforma.
Steve K,

34

Ho eseguito alcuni test di temporizzazione perché il tempo conta, sempre.

Ho provato a ottenere la risposta in una stringa 3 in diversi modi. (mostrato sotto)
Ho lasciato fuori i blocchi try / catch per la leggibilità del bene.

Per dare contesto, questo è il codice precedente per tutti e 3 gli approcci:

   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();

Quindi, dopo aver eseguito 500 test su ciascun approccio con gli stessi dati di richiesta / risposta, ecco i numeri. Ancora una volta, questi sono i miei risultati e i tuoi risultati potrebbero non essere esattamente gli stessi, ma ho scritto questo per dare qualche indicazione agli altri sulle differenze di efficienza di questi approcci.

Ranghi:
Approccio n. 1
Approccio n. 3 - 2,6% più lento del n. 1
Approccio n. 2 - 4,3% più lento del n. 1

Ognuno di questi approcci è una soluzione appropriata per afferrare una risposta e creare una stringa da essa.


2
2) contiene un errore, aggiunge sempre "null" alla fine della stringa poiché fai sempre un altro passo del necessario. Le prestazioni saranno le stesse comunque penso. Dovrebbe funzionare: String read = null; StringBuffer sb = new StringBuffer (); while ((read = br.readLine ())! = null) {sb.append (leggi); }
LukeSolar,

Va notato che GetMethod fa parte di org.apache.commons.httpclient, non di Java standard
jk7

L'approccio n. 2 consumerà '\ n' se il file ha molte righe, questa non dovrebbe essere la risposta
Ninja

33

La soluzione Java pura che utilizza Stream s funziona da 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()));
    }
}

Come indicato da Christoffer Hammarström sotto un'altra risposta , è più sicuro specificare esplicitamente il set di caratteri . Vale a dire il costruttore InputStreamReader può essere modificato come segue:

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

11
Invece di fare Charset.forName("UTF-8"), usa StandardCharsets.UTF_8(da java.nio.charset).
robinst,

26

Ecco la risposta più o meno campionaria, ripulita un po 'e rappresentata come una funzione:

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

Se non puoi usare Commons IO (FileUtils / IOUtils / CopyUtils), ecco un esempio usando un BufferedReader per leggere il file riga per riga:

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);
    }
}

Oppure, se vuoi la velocità pura, proporrei una variazione su ciò che Paul de Vrieze ha suggerito (che evita di usare StringWriter (che utilizza uno 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);
    }
}

Per far funzionare il tuo codice, ho dovuto usare this.getClass (). GetClassLoader (). GetResourceAsStream () (usando Eclipse con un progetto
maven

19

Questo è carino perché:

  • Gestisce in sicurezza Charset.
  • Controlli la dimensione del buffer di lettura.
  • È possibile eseguire il provisioning della lunghezza del builder e non deve essere un valore esatto.
  • È libero dalle dipendenze delle biblioteche.
  • È per Java 7 o versioni successive.

Come farlo?

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();
}

Per JDK 9

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

1
Non catch (Throwable)dovrebbe essere vuoto se si tratta di codice di produzione.
Christian Hujer,

1
cosa mettere in questa dichiarazione catch-gettabile?
alex,

Sebbene l'utilizzo di UTF-8 sia generalmente ragionevole, non si deve supporre che i caratteri siano codificati in questo modo.
Martin,

18

Questa è una risposta adattata dal org.apache.commons.io.IOUtils codice sorgente , per coloro che vogliono avere l'implementazione di Apache ma non vogliono l'intera libreria.

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

Assicurati di chiudere i flussi alla fine se usi i lettori di stream

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();
}

EDIT: su JDK 7+, puoi usare il costrutto try-with-resources.

/**
 * 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
Hai ragione a chiudere i flussi, tuttavia, la responsabilità di chiudere i flussi è di solito con il costruttore del flusso (termina ciò che inizi). Quindi, iStreamdovrebbe piuttosto essere chiuso dal chiamante perché il chiamante ha creato iStream. Inoltre, i flussi di chiusura dovrebbero essere eseguiti in un finallyblocco, o meglio in un'istruzione try-with-resources di Java 7. Nel tuo codice, quando readLine()genera IOExceptiono builder.append()genera OutOfMemoryError, i flussi rimarrebbero aperti.
Christian Hujer,

16

Un altro, per tutti gli utenti di 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);
}

I metodi di utilità in org.springframework.util.StreamUtilssono simili a quelli in FileCopyUtils, ma al termine lasciano lo stream aperto.


16

Utilizzare java.io.InputStream.transferTo (OutputStream) supportato in Java 9 e ByteArrayOutputStream.toString (String) che assume il nome del set di caratteri:

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

Cosa hai passato per il nome del set di caratteri nel tuo caso?
Virsha,

1
@virsha Devi determinarlo dalla fonte che ha fornito InputStream. Ricorda che non ha senso avere una stringa senza sapere quale codifica utilizza.
jmehrens,

15

Ecco il metodo completo per la conversione InputStreamin Stringsenza utilizzare alcuna libreria di terze parti. Utilizzare StringBuilderper ambiente a thread singolo altrimenti utilizzare 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
In questo metodo non è stata applicata alcuna codifica. Quindi supponiamo che i dati ricevuti da InputStream siano codificati usando UTF-8, l'output sarà errato. Per risolvere questo problema è possibile utilizzare in = new InputStreamReader(inputStream)e (char)in.read().
Frederic Leitenberger,

2
e memoria inefficiente pure; Credo di aver provato a usarlo prima su un input di grandi dimensioni e StringBuilder ha esaurito la memoria
gengkev,

1
C'è un'altra risposta simile che utilizza un buffer char [] ed è più efficiente e si occupa del set di caratteri.
Guillaume Perrot,

14

Ecco come farlo usando solo JDK usando i buffer di array di byte. Questo è in realtà il modo in cui IOUtils.copy()funzionano tutti i metodi comuni . Puoi sostituirlo byte[]con char[]se stai copiando da un Readerinvece di 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
Fornisci una descrizione di ciò che stai cercando di realizzare.
Ragunath Jawahar,

14

Gli utenti di Kotlin semplicemente fanno:

println(InputStreamReader(is).readText())

mentre

readText()

è il metodo di estensione incorporato della libreria standard Kotlin.


Questo in realtà non è del tutto corretto perché non chiude il flusso. Lo consiglierei is.bufferedReader().use { it.readText() }.
Max

9

Il modo più semplice in JDK è con i seguenti frammenti di codice.

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

7

Ecco la mia soluzione basata su Java 8 , che utilizza la nuova API Stream per raccogliere tutte le righe da 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
Sembra che in realtà non hai letto tutte le risposte postate prima. La versione dell'API Stream era già qui almeno due volte .
Tagir Valeev,

Ho esaminato tutte le soluzioni, ma non ho trovato adatto. Trovo che due righe con una breve descrizione siano presentate in modo preciso. Ad esempio, il blocco try-catch dell'altra soluzione non viene mai utilizzato. Ma hai ragione. Con così tante risposte sono passato alla modalità di lettura a salto rapido ... :-)
Christian Rädel,

1
Non stai leggendo il file originale, stai convertendo le terminazioni di riga del file in qualsiasi terminazioni di riga del sistema operativo, possibilmente modificando il contenuto del file.
Christian Hujer,

7

In termini di reduce, e concatpuò essere espresso in Java 8 come:

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

1
Sarà follemente lento.
Tagir Valeev,

Interessante, perché? Potresti elaborare?
libnull-dev,

1
non sai perché concatenare le stringhe in loop invece di usare StringBuilder è una cattiva idea?
Tagir Valeev,

Hai ragione. StringBuilderpotrebbe essere più efficiente. Controllerò, ma il mio punto era mostrare un approccio più funzionale con immutabile String.
libnull-dev,

Gli approcci funzionali sono interessanti ma di solito molto inefficienti.
Lluis Martinez,

4

Risposta JDK 7/8 che chiude lo stream e genera ancora un'eccezione 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));
  }
}
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.