4724 Stimmen

Wie lese/konvertiere ich einen InputStream in einen String in Java?

Wenn Sie eine java.io.InputStream Objekt, wie sollten Sie dieses Objekt verarbeiten und eine String ?


Angenommen, ich habe eine InputStream die Textdaten enthält, und ich möchte sie in eine String so dass ich das zum Beispiel in eine Protokolldatei schreiben kann.

Wie kann man am einfachsten die InputStream und konvertieren sie in eine String ?

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

0 Stimmen

2 Stimmen

Denken Sie daran, dass Sie die Kodierung des Eingangsstroms berücksichtigen müssen. Die Systemvorgabe ist nicht unbedingt immer die, die Sie wollen.

23 Stimmen

Die meisten dieser Antworten wurden vor Java 9 geschrieben, aber jetzt kann man mit .readAllBytes ein Byte-Array aus dem InputStream holen. Also, einfach "new String(inputStream.readAllBytes())" funktioniert mit dem byte[] Konstruktor von String.

68voto

Drew Noakes Punkte 282438

Hier ist die eleganteste, reine Java-Lösung (ohne Bibliothek), die mir nach einigen Experimenten eingefallen ist:

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

67voto

Ilya Gazman Punkte 29734

Ich habe einen Benchmark durchgeführt und bin dabei auf 14 verschiedene Antworten gestoßen (es tut mir leid, dass ich keine Credits angegeben habe, aber es gibt zu viele Duplikate).

Das Ergebnis ist sehr überraschend. Es stellt sich heraus, dass Apache IOUtils ist die langsamste und ByteArrayOutputStream ist die schnellste Lösung:

Hier ist also zunächst die beste Methode:

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

Benchmark-Ergebnisse, 20 MB zufällige Bytes in 20 Zyklen

Zeit in Millisekunden

  • ByteArrayOutputStreamTest: 194
  • NioStream: 198
  • Java9ISTransferTo: 201
  • Java9ISReadAllBytes: 205
  • BufferedInputStreamVsByteArrayOutputStream: 314
  • ApacheStringWriter2: 574
  • GuavaCharStreams: 589
  • ScannerReaderNoNextTest: 614
  • ScannerReader: 633
  • ApacheStringWriter: 1544
  • StreamApi: Fehler
  • ParallelStreamApi: Fehler
  • BufferReaderTest: Fehler
  • InputStreamAndStringBuilder: Fehler

Benchmark-Quellcode

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

}

0 Stimmen

Benchmarks in Java zu erstellen ist nicht einfach (insbesondere wegen JIT). Nachdem ich den Benchmark-Quellcode gelesen habe, bin ich davon überzeugt, dass die oben genannten Werte nicht präzise sind und jeder vorsichtig sein sollte, wenn er ihnen Glauben schenkt.

0 Stimmen

@Dalibor, Sie sollten Ihre Behauptung besser begründen, als nur einen Link anzugeben.

0 Stimmen

Ich glaube, es ist wirklich bekannt, dass es nicht einfach ist, einen eigenen Benchmark zu erstellen. Für diejenigen, die das nicht wissen, gibt es einen Link ;)

44voto

Simon Kuang Punkte 3750

Ich würde einige Java 8-Tricks anwenden.

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.
    }
}

Im Wesentlichen dasselbe wie einige andere Antworten, nur etwas knapper.

40voto

Brett Holt Punkte 1129

Ich habe einige Zeittests durchgeführt, denn Zeit ist immer wichtig.

Ich habe auf 3 verschiedene Arten versucht, die Antwort in einen String zu übertragen. (siehe unten)
Ich habe try/catch-Blöcke der Lesbarkeit halber weggelassen.

Um den Zusammenhang zu verdeutlichen, ist dies der vorangehende Code für alle 3 Ansätze:

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

Nachdem ich also 500 Tests für jeden Ansatz mit denselben Anfrage-/Antwortdaten durchgeführt habe, sind hier die Zahlen. Noch einmal: Dies sind meine Ergebnisse, und Ihre Ergebnisse sind vielleicht nicht genau dieselben, aber ich habe dies geschrieben, um anderen einen Hinweis auf die Effizienzunterschiede dieser Ansätze zu geben.

Ränge:
Ansatz 1
Ansatz #3 - 2,6% langsamer als #1
Ansatz #2 - 4,3% langsamer als #1

Jeder dieser Ansätze ist eine geeignete Lösung, um eine Antwort zu erfassen und daraus einen String zu erstellen.

39voto

czerny Punkte 12815

Reine Java-Lösung mit Stream s, funktioniert seit 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()));
    }
}

Wie von Christoffer Hammarström weiter unten erwähnt andere Antwort ist es sicherer, explizit die Zeichensatz . D.h. der InputStreamReader-Konstruktor kann wie folgt geändert werden:

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

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X