Ich war überrascht, heute festzustellen, dass ich keine einfache Möglichkeit finden konnte, den Inhalt eines zu schreiben InputStream
eines OutputStream
in Java . Natürlich ist der Byte-Puffer-Code nicht schwer zu schreiben, aber ich vermute, ich vermisse nur etwas, das mein Leben einfacher machen würde (und den Code klarer macht).
Gibt es also angesichts von InputStream
in
und OutputStream
out
eine einfachere Möglichkeit, Folgendes zu schreiben?
byte[] buffer = new byte[1024];
int len = in.read(buffer);
while (len != -1) {
out.write(buffer, 0, len);
len = in.read(buffer);
}
Antworten:
Java 9
InputStream
Bietet seit Java 9 eine MethodetransferTo
mit der folgenden Signatur:Wie in der Dokumentation angegeben ,
transferTo
wird:Um also den Inhalt eines Java
InputStream
in einen zu schreibenOutputStream
, können Sie schreiben:quelle
Files.copy
so viel wie möglich bevorzugen . Es ist in nativem Code implementiert und kann daher schneller sein.transferTo
sollte nur verwendet werden, wenn beide Streams nicht FileInputStream / FileOutputStream sind.Files.copy
behandelt nicht alle Eingabe / Ausgabe - Streams , aber es ist speziell für entworfen Datei - Streams.Wie WMR erwähnt hat, hat
org.apache.commons.io.IOUtils
Apache eine Methode namens,copy(InputStream,OutputStream)
die genau das tut, wonach Sie suchen.Also hast du:
... in Ihrem Code.
Gibt es einen Grund, den Sie vermeiden
IOUtils
?quelle
in
undout
muss am Ende des Codes in einem finally-Block geschlossen werdenWenn Sie Java 7 verwenden, ist Dateien (in der Standardbibliothek) der beste Ansatz:
Bearbeiten: Natürlich ist es nur nützlich, wenn Sie einen InputStream oder OutputStream aus einer Datei erstellen. Verwenden Sie
file.toPath()
diese Option , um den Pfad aus der Datei abzurufen.Um in eine vorhandene Datei zu schreiben (z. B. eine, die mit erstellt wurde
File.createTempFile()
), müssen Sie dieREPLACE_EXISTING
Kopieroption übergeben (andernfallsFileAlreadyExistsException
wird sie ausgelöst):quelle
Files
ist NICHT in Java 1.7 von Android verfügbar . Ich wurde dadurch gestochen: stackoverflow.com/questions/24869323/…Files.copy()
der zwei Streams benötigt, und auf den sich alle anderenFiles.copy()
Funktionen beziehen, um die eigentliche Kopierarbeit zu erledigen. Es ist jedoch privat (da es zu diesem Zeitpunkt tatsächlich keine Pfade oder Dateien enthält) und sieht genauso aus wie der Code in der eigenen Frage des OP (plus eine return-Anweisung). Kein Öffnen, kein Schließen, nur eine Kopierschleife.Ich denke, das wird funktionieren, aber stellen Sie sicher, dass Sie es testen ... geringfügige "Verbesserung", aber es könnte ein bisschen teuer für die Lesbarkeit sein.
quelle
while(len > 0)
stattdessen sagen!= -1
, da letztere bei Verwendung derread(byte b[], int off, int len)
out.write
InputStream
Vertrag völlig legal ist, dass read 0 beliebig oft zurückgibt . Und lautOutputStream
Vertrag muss die Schreibmethode eine Länge von 0 akzeptieren und sollte nur dann eine Ausnahme auslösen, wenn sielen
negativ ist.while
in a ändernfor
und eine der Variablen in den Init-Abschnitt von for einfügen: zfor (int n ; (n = in.read(buf)) != -1 ;) out.write(buf, 0, n);
. =)read()
kann nur dann Null zurückgeben, wenn Sie eine Länge von Null angegeben haben, was ein Programmierfehler und eine dumme Bedingung wäre, die für immer wiederholt werden muss. Undwrite()
löst keine Ausnahme aus, wenn Sie eine Länge von Null angeben.Verwenden von Guaven
ByteStreams.copy()
:quelle
Files.copy
so viel wie möglich verwenden. Verwenden SieByteStreams.copy
nur dann , wenn beide Ströme sind nicht Fileinputstream / Outputstream.Einfache Funktion
Wenn Sie dies nur zum Schreiben eines
InputStream
an a benötigenFile
, können Sie diese einfache Funktion verwenden:quelle
close()
Anrufe jedoch infinally
Blöcken platzieren?Das
JDK
verwendet den gleichen Code, so dass es den Anschein hat, als gäbe es keinen "einfacheren" Weg ohne klobige Bibliotheken von Drittanbietern (die wahrscheinlich sowieso nichts anderes machen). Folgendes wird direkt kopiert vonjava.nio.file.Files.java
:quelle
PipedInputStream
undPipedOutputStream
sollte nur verwendet werden, wenn Sie mehrere Threads haben, wie vom Javadoc angegeben .Beachten Sie außerdem, dass Eingabestreams und Ausgabestreams keine Thread-Unterbrechungen mit
IOException
s umschließen. Sie sollten daher in Betracht ziehen, eine Unterbrechungsrichtlinie in Ihren Code aufzunehmen:Dies ist eine nützliche Ergänzung, wenn Sie diese API zum Kopieren großer Datenmengen oder von Daten aus Streams verwenden möchten, die unerträglich lange hängen bleiben.
quelle
Für diejenigen, die das Spring Framework verwenden, gibt es eine nützliche StreamUtils- Klasse:
Das Obige schließt die Streams nicht. Wenn Sie möchten, dass die Streams nach dem Kopieren geschlossen werden, verwenden Sie stattdessen die FileCopyUtils- Klasse:
quelle
Es gibt keine Möglichkeit, dies mit JDK-Methoden viel einfacher zu machen, aber wie Apocalisp bereits bemerkt hat, sind Sie nicht der einzige mit dieser Idee: Sie könnten IOUtils von Jakarta Commons IO verwenden , es hat auch viele andere nützliche Dinge, dass IMO eigentlich Teil des JDK sein sollte ...
quelle
Mit Java7 und Try-with-Resources wird eine vereinfachte und lesbare Version geliefert .
quelle
Hier kommt, wie ich es mit der einfachsten for-Schleife mache.
quelle
Verwenden Sie die Util-Klasse von Commons Net:
quelle
Ein meiner Meinung nach minimaleres Snippet (das auch die Längenvariable enger zusammenfasst):
Als Randnotiz verstehe ich nicht, warum mehr Leute keine
for
Schleife verwenden, sondern sich für einenwhile
mit einem Zuweisungs- und Testausdruck entscheiden, der von einigen als "schlechter" Stil angesehen wird.quelle
for(int n = 0; (n = in.read(buffer)) > 0;) { out.write(buffer, 0, n); }
Das ist mein bester Schuss !!
Und nicht verwenden,
inputStream.transferTo(...)
weil es zu allgemein ist. Ihre Codeleistung ist besser, wenn Sie Ihren Pufferspeicher steuern.Ich benutze es mit dieser (verbesserungsfähigen) Methode, wenn ich die Größe des Streams im Voraus kenne.
quelle
Ich denke, es ist besser, einen großen Puffer zu verwenden, da die meisten Dateien größer als 1024 Bytes sind. Es ist auch eine gute Praxis, die Anzahl der gelesenen Bytes zu überprüfen, um positiv zu sein.
quelle
Ich benutze
BufferedInputStream
undBufferedOutputStream
, um die Puffersemantik aus dem Code zu entfernenquelle
PipedInputStream und PipedOutputStream können von Nutzen sein, da Sie eine Verbindung miteinander herstellen können.
quelle
Ein weiterer möglicher Kandidat sind die Guava I / O-Dienstprogramme:
http://code.google.com/p/guava-libraries/wiki/IOExplained
Ich dachte, ich würde diese verwenden, da Guava in meinem Projekt bereits sehr nützlich ist, anstatt eine weitere Bibliothek für eine Funktion hinzuzufügen.
quelle
copy
undtoByteArray
Methoden in docs.guava-libraries.googlecode.com/git-history/release/javadoc/… (Guave nennt Eingabe- / Ausgabestreams als "Byte-Streams" und Leser / Writer als "Char-Streams")Nicht sehr lesbar, aber effektiv, hat keine Abhängigkeiten und läuft mit jeder Java-Version
quelle
!= -1
oder> 0
? Diese Prädikate sind nicht ganz gleich.quelle
Probieren Sie Kakteen :
Weitere Details hier: http://www.yegor256.com/2017/06/22/object-oriented-input-output-in-cactoos.html
quelle
Sie können diese Methode verwenden
quelle
catch(Exception ex){}
- das ist erstklassig