Wenn Sie ein java.io.InputStream
Objekt haben, wie sollten Sie dieses Objekt verarbeiten und ein Objekt erstellen String
?
Angenommen, ich habe eine InputStream
, die Textdaten enthält, und ich möchte sie in eine konvertieren String
, damit ich sie beispielsweise in eine Protokolldatei schreiben kann.
Was ist der einfachste Weg, das zu nehmen InputStream
und es in ein umzuwandeln String
?
public String convertStreamToString(InputStream is) {
// ???
}
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);
String s = Files.readString(Path.of("SomeFile.txt"));
was so gut wie eine Sprache ist, die niemals solche magischen Konvertierungen wie die von Ihnen beschriebene unterstützt.Antworten:
Ein guter Weg, dies zu tun, ist die Verwendung von Apache Commons,
IOUtils
um dasInputStream
in einStringWriter
... so etwas wie zu kopierenoder auch
Alternativ können Sie verwenden,
ByteArrayOutputStream
wenn Sie Ihre Streams und Writer nicht mischen möchtenquelle
Fassen Sie andere Antworten zusammen. Ich habe 11 Hauptmethoden gefunden, um dies zu tun (siehe unten). Und ich habe einige Leistungstests geschrieben (siehe Ergebnisse unten):
Möglichkeiten zum Konvertieren eines InputStream in einen String:
Verwenden von
IOUtils.toString
(Apache Utils)Verwenden von
CharStreams
(Guave)Verwenden von
Scanner
(JDK)Verwenden der Stream-API (Java 8). Warnung : Diese Lösung konvertiert verschiedene Zeilenumbrüche (wie
\r\n
) in\n
.Verwenden der parallelen Stream-API (Java 8). Warnung : Diese Lösung konvertiert verschiedene Zeilenumbrüche (wie
\r\n
) in\n
.Verwenden von
InputStreamReader
undStringBuilder
(JDK)Verwenden von
StringWriter
undIOUtils.copy
(Apache Commons)Verwenden von
ByteArrayOutputStream
undinputStream.read
(JDK)Verwenden von
BufferedReader
(JDK). Warnung: Diese Lösung konvertiert verschiedene Zeilenumbrüche (wie\n\r
) inline.separator
Systemeigenschaften (z. B. in Windows in "\ r \ n").Verwenden von
BufferedInputStream
undByteArrayOutputStream
(JDK)Verwenden von
inputStream.read()
undStringBuilder
(JDK). Warnung : Diese Lösung hat Probleme mit Unicode, z. B. mit russischem Text (funktioniert nur mit Nicht-Unicode-Text korrekt).Warnung :
Die Lösungen 4, 5 und 9 konvertieren verschiedene Zeilenumbrüche in einen.
Lösung 11 kann mit Unicode-Text nicht richtig funktionieren
Leistungstests
Leistungstests für kleine
String
(Länge = 175), URL in Github (Modus = durchschnittliche Zeit, System = Linux, Punktzahl 1.343 ist die beste):Leistungstests für große
String
(Länge = 50100), URL in Github (Modus = durchschnittliche Zeit, System = Linux, Punktzahl 200.715 ist die beste):Diagramme (Leistungstests abhängig von der Länge des Eingabestreams im Windows 7-System)
Leistungstest (durchschnittliche Zeit) abhängig von der Länge des Eingabestreams im Windows 7-System:
quelle
\r\n
) konvertieren, in\n
die in einigen Fällen unerwünscht sein kann. Es wäre auch schön, den zusätzlichen Speicherbedarf oder zumindest den Zuordnungsdruck zu sehen (zumindest können Sie JMH mit ausführen-prof gc
). Für den wirklich coolen Beitrag wäre es großartig, die Grafiken zu sehen (abhängig von der Zeichenfolgenlänge innerhalb derselben Eingabegröße und abhängig von der Eingabegröße innerhalb derselben Zeichenfolgenlänge).reset()
in Beispiel 11?Hier ist eine Möglichkeit, nur die Standard-Java-Bibliothek zu verwenden (beachten Sie, dass der Stream nicht geschlossen ist, Ihr Kilometerstand kann variieren).
Ich habe diesen Trick aus dem Artikel "Dumme Scanner-Tricks" gelernt . Der Grund dafür ist, dass der Scanner über Token im Stream iteriert. In diesem Fall trennen wir Token mithilfe des "Beginns der Eingabegrenze" (\ A), sodass wir nur ein Token für den gesamten Inhalt des Streams erhalten.
Hinweis: Wenn Sie die Codierung des Eingabestreams genau
Scanner
angeben müssen , können Sie dem Konstruktor das zweite Argument bereitstellen, das angibt, welcher Zeichensatz verwendet werden soll (z. B. "UTF-8").Die Hutspitze geht auch an Jacob , der mich einmal auf den genannten Artikel hingewiesen hat.
quelle
if (is == null) return "";
gleich zu Beginn der Methode hinzufügen ; Ich glaube, diese Antwort muss aktualisiert werden, um null inputStreams besser verarbeiten zu können.try(java.util.Scanner s = new java.util.Scanner(is)) { return s.useDelimiter("\\A").hasNext() ? s.next() : ""; }
Apache Commons erlaubt:
Natürlich können Sie neben UTF-8 auch andere Zeichenkodierungen wählen.
Siehe auch: ( Dokumentation )
quelle
Unter Berücksichtigung der Datei sollte man zuerst eine
java.io.Reader
Instanz bekommen. Dies kann dann gelesen und zu a hinzugefügt werdenStringBuilder
(wir brauchen es nicht,StringBuffer
wenn wir nicht in mehreren Threads darauf zugreifen, und esStringBuilder
ist schneller). Der Trick dabei ist, dass wir in Blöcken arbeiten und daher keine anderen Pufferströme benötigen. Die Blockgröße wird zur Laufzeitleistungsoptimierung parametriert.quelle
In our product, I even replaced
sollte "wir haben sogar ersetzt" sein.Verwenden:
quelle
readLine
Zeichen für Zeichen nach EOL gesucht wird. Auch wenn der Stream keinen Zeilenumbruch enthält, ist dies nicht wirklich sinnvoll.Wenn Sie Google-Collections / Guava verwenden, können Sie Folgendes tun:
Beachten Sie, dass der zweite Parameter (dh Charsets.UTF_8) für das
InputStreamReader
nicht erforderlich ist, aber es ist im Allgemeinen eine gute Idee, die Codierung anzugeben, wenn Sie sie kennen (was Sie sollten!).quelle
Dies ist die beste reine Java-Lösung, die perfekt für Android und jede andere JVM geeignet ist.
Diese Lösung funktioniert erstaunlich gut ... sie ist einfach, schnell und funktioniert trotzdem bei kleinen und großen Streams !! (siehe Benchmark oben .. Nr. 8 )
quelle
2*n
, wobei n die Größe des Streams gemäß demByteArrayInputStream
automatisch wachsenden System ist.Der Vollständigkeit halber hier die Java 9- Lösung:
Das
readAllBytes
befindet sich derzeit in der JDK 9-Hauptcodebasis, sodass es wahrscheinlich in der Version erscheint. Sie können es jetzt mit den JDK 9-Snapshot-Builds versuchen .quelle
byte[] buf = new byte[DEFAULT_BUFFER_SIZE];
woMAX_BUFFER_SIZE = Integer.MAX_VALUE - 8;
was gibtMAX_BUFFER_SIZE = 2147483639
. Google sagt, es ist rund 2.147 GB.InputStream
, nicht umPath
. DieInputStream
können aus vielen verschiedenen Quellen erstellt werden, nicht nur aus Dateien.byte[]
Implementierung, wenn sich alle Zeichen in den ersten 256 Codepunkten befinden. Dies bedeutet, dass der neue String (Byte [], "ISO-Latin-1") eine einfache Array-Kopie ist.Verwenden:
quelle
BufferedInputStream
. Die zugrunde liegenden Lesevorgänge betragen jeweils 8192 Byte.BufferedInputStream
und Einlesen in einen Byte-Array-Puffer anstelle von jeweils einem Byte. Beispiel: 200 ms gegenüber 60 ms beim Lesen einer 4,56-MiB-Datei.buf.toString()
.Hier ist die eleganteste reine Java-Lösung (keine Bibliothek), die ich nach einigen Experimenten gefunden habe:
quelle
InputStream
sollte vom Anrufer geschlossen werden.readLine
? Wenn Sie die Zeilen an sich nicht verwenden, wasIch habe hier einen Benchmark für 14 verschiedene Antworten durchgeführt (Entschuldigung, dass ich keine Credits bereitgestellt habe, aber es gibt zu viele Duplikate).
Das Ergebnis ist sehr überraschend. Es stellt sich heraus, dass Apache IOUtils am langsamsten ist und
ByteArrayOutputStream
schnellste Lösung ist:Hier ist also zuerst die beste Methode:
Benchmark-Ergebnisse von 20 MB zufälligen Bytes in 20 Zyklen
Zeit in Millisekunden
Benchmark-Quellcode
quelle
Ich würde einige Java 8-Tricks verwenden.
Im Wesentlichen dasselbe wie einige andere Antworten, außer prägnanter.
quelle
return null
jemals genannt werden? Entweder diebr.lines...
Rückgabe oder eine Ausnahme wird ausgelöst.parallel()
den Stream an?\r\n
in\n
... konvertiert würdenSystem.lineSeparator()
das entsprechende plattformabhängige Zeilenende verwenden.Ich habe einige Timing-Tests durchgeführt, weil die Zeit immer wichtig ist.
Ich habe versucht, die Antwort auf verschiedene Arten in einen String 3 umzuwandeln. (siehe unten)
Ich habe Try / Catch-Blöcke aus Gründen der Lesbarkeit weggelassen.
Um den Kontext anzugeben, ist dies der vorhergehende Code für alle drei Ansätze:
1)
2)
3)
Nach 500 Tests für jeden Ansatz mit denselben Anforderungs- / Antwortdaten sind hier die Zahlen aufgeführt. Dies sind wieder meine Ergebnisse, und Ihre Ergebnisse sind möglicherweise nicht genau dieselben, aber ich habe dies geschrieben, um anderen einen Hinweis auf die Effizienzunterschiede dieser Ansätze zu geben.
Ränge:
Ansatz Nr. 1
Ansatz Nr. 3 - 2,6% langsamer als Nr. 1
Ansatz Nr. 2 - 4,3% langsamer als Nr. 1
Jeder dieser Ansätze ist eine geeignete Lösung, um eine Antwort zu erfassen und daraus einen String zu erstellen.
quelle
Reine Java-Lösung mit Streams , funktioniert seit Java 8.
Wie von Christoffer Hammarström unter anderen Antworten erwähnt , ist es sicherer, den Zeichensatz explizit anzugeben . Dh der InputStreamReader-Konstruktor kann wie folgt geändert werden:
quelle
Charset.forName("UTF-8")
Verwenden Sie stattdessenStandardCharsets.UTF_8
(fromjava.nio.charset
).Hier ist mehr oder weniger die Antwort von Sampath, die ein wenig aufgeräumt und als Funktion dargestellt wurde:
quelle
Wenn Sie sich abenteuerlustig fühlen, können Sie Scala und Java mischen und am Ende Folgendes erreichen:
Das Mischen von Java- und Scala-Code und -Bibliotheken hat seine Vorteile.
Die vollständige Beschreibung finden Sie hier: Idiomatische Methode zum Konvertieren eines InputStream in einen String in Scala
quelle
Source.fromInputStream(...).mkString
Wenn Sie Commons IO (FileUtils / IOUtils / CopyUtils) nicht verwenden können, finden Sie hier ein Beispiel mit einem BufferedReader, um die Datei Zeile für Zeile zu lesen:
Oder wenn Sie rohe Geschwindigkeit wünschen, würde ich eine Variation dessen vorschlagen, was Paul de Vrieze vorgeschlagen hat (wodurch die Verwendung eines StringWriter vermieden wird (der intern einen StringBuffer verwendet):
quelle
Dieser ist schön, weil:
Wie es geht?
Für JDK 9
quelle
catch (Throwable)
sollte nicht wirklich leer sein, wenn dies Produktionscode ist.Dies ist eine aus dem
org.apache.commons.io.IOUtils
Quellcode angepasste Antwort für diejenigen, die die Apache-Implementierung haben möchten, aber nicht die gesamte Bibliothek.quelle
Stellen Sie sicher, dass Sie die Streams am Ende schließen, wenn Sie Stream Readers verwenden
BEARBEITEN: Unter JDK 7+ können Sie das Konstrukt "Try-with-Resources" verwenden.
quelle
iStream
sollte eigentlich lieber vom Anrufer geschlossen werden, weil der Anrufer erstellt hatiStream
. Außerdem sollte das Schließen von Streams in einemfinally
Block oder noch besser in einer Java 7-Try-with-Resources-Anweisung erfolgen. In Ihrem Code bleiben die Streams beimreadLine()
WerfenIOException
oderbuilder.append()
WerfenOutOfMemoryError
offen.Eine weitere für alle Spring-Benutzer:
Die Dienstprogrammmethoden in
org.springframework.util.StreamUtils
ähneln denen inFileCopyUtils
, lassen den Stream jedoch offen, wenn sie fertig sind.quelle
Verwenden Sie java.io.InputStream.transferTo (OutputStream), das in Java 9 unterstützt wird, und ByteArrayOutputStream.toString (String), das den Zeichensatznamen verwendet:
quelle
Hier finden Sie die vollständige Methode zum Konvertieren
InputStream
inString
eine Bibliothek eines Drittanbieters. VerwendungStringBuilder
für Single - Threaded - Umgebung anderweitig nutzenStringBuffer
.quelle
in = new InputStreamReader(inputStream)
und verwenden(char)in.read()
.Hier erfahren Sie, wie Sie dies nur mit dem JDK mithilfe von Byte-Array-Puffern tun. So funktionieren eigentlich
IOUtils.copy()
alle Commons-Io- Methoden. Sie können ersetzenbyte[]
mit ,char[]
wenn Sie von einem sind das KopierenReader
statt einInputStream
.quelle
Kotlin-Benutzer tun einfach:
wohingegen
ist die integrierte Erweiterungsmethode der Kotlin-Standardbibliothek.
quelle
is.bufferedReader().use { it.readText() }
.Der einfachste Weg in JDK ist mit den folgenden Code-Snipplets.
quelle
Hier ist meine Java 8- basierte Lösung, die die neue Stream-API verwendet , um alle Zeilen von einem zu sammeln
InputStream
:quelle
In Bezug auf
reduce
undconcat
kann es in Java 8 ausgedrückt werden als:quelle
StringBuilder
könnte effizienter sein. Ich werde es überprüfen, aber mein Ziel war es, einen funktionaleren Ansatz mit unveränderlichem Ansatz zu zeigenString
.JDK 7/8-Antwort, die den Stream schließt und dennoch eine IOException auslöst:
quelle