Ich bin in der Entwicklungsphase, wo ich zwei Module habe und von einem habe ich als OutputStream
und als zweites ausgegeben , was nur akzeptiert wird InputStream
. Wissen Sie , wie zu konvertieren , OutputStream
um InputStream
(nicht umgekehrt, ich meine wirklich so) , dass ich in der Lage sein wird , diese beiden Teile zu verbinden?
Vielen Dank
java
inputstream
outputstream
Wegpunkt
quelle
quelle
new YourOutputStream(thePipedOutputStream)
undnew YourInputStream(thePipedInputStream)
dies ist wahrscheinlich nicht die Art und Weise, wie Ihr Stream funktioniert. Ich denke also nicht, dass dies die Lösung ist.Antworten:
An
OutputStream
ist einer, in den Sie Daten schreiben. Wenn ein Modul ein verfügbar machtOutputStream
, wird erwartet, dass am anderen Ende etwas gelesen wird.Etwas, das ein aufdeckt
InputStream
, zeigt andererseits an, dass Sie diesen Stream anhören müssen, und es gibt Daten, die Sie lesen können.So ist es möglich, ein
InputStream
mit einem zu verbindenOutputStream
InputStream----read---> intermediateBytes[n] ----write----> OutputStream
Wie jemand sagte, können Sie dies mit der
copy()
Methode von IOUtils tun. Es macht keinen Sinn, in die andere Richtung zu gehen ... hoffentlich macht das SinnAKTUALISIEREN:
Je mehr ich darüber nachdenke, desto mehr kann ich natürlich sehen, wie dies tatsächlich erforderlich wäre. Ich kenne einige der Kommentare, in denen
Piped
Eingabe- / Ausgabestreams erwähnt wurden, aber es gibt eine andere Möglichkeit.Wenn der exponierte Ausgabestream a ist
ByteArrayOutputStream
, können Sie jederzeit den vollständigen Inhalt abrufen, indem Sie dietoByteArray()
Methode aufrufen . Anschließend können Sie mithilfe derByteArrayInputStream
Unterklasse einen Eingabestream-Wrapper erstellen . Diese beiden sind Pseudo-Streams, beide umschließen im Grunde nur ein Array von Bytes. Die Verwendung der Streams auf diese Weise ist daher technisch möglich, aber für mich ist es immer noch sehr seltsam ...quelle
Es scheint viele Links und ähnliches zu geben, aber keinen tatsächlichen Code, der Pipes verwendet. Der Vorteil von
java.io.PipedInputStream
undjava.io.PipedOutputStream
besteht darin, dass kein zusätzlicher Speicherverbrauch anfällt.ByteArrayOutputStream.toByteArray()
Gibt eine Kopie des ursprünglichen Puffers zurück. Das bedeutet, dass Sie jetzt zwei Kopien davon haben, was auch immer Sie im Speicher haben. WennInputStream
Sie dann auf ein schreiben, haben Sie jetzt drei Kopien der Daten.Der Code:
Dieser Code setzt voraus, dass
originalByteArrayOutputStream
es sich um einen handelt,ByteArrayOutputStream
da dies normalerweise der einzige verwendbare Ausgabestream ist, es sei denn, Sie schreiben in eine Datei. Ich hoffe das hilft! Das Tolle daran ist, dass es, da es sich in einem separaten Thread befindet, auch parallel funktioniert. Was also Ihren Eingabestream verbraucht, wird auch aus Ihrem alten Ausgabestream gestreamt. Dies ist vorteilhaft, da der Puffer kleiner bleiben kann und Sie weniger Latenz und weniger Speicher benötigen.quelle
out
anin
den Konstruktor zu übergeben, da Sie sonstin
aufgrund der Rennbedingungen (die ich erlebt habe) möglicherweise eine Ausnahme für geschlossene Rohre erhalten . Verwenden von Java 8 Lambdas:PipedInputStream in = new PipedInputStream(out); ((Runnable)() -> {originalOutputStream.writeTo(out);}).run(); return in;
originalOutputStream
was wahr sein sollte, aber er setzt nicht voraus, wie Sie Ihre Streams steuern. Das bleibt dem Entwickler überlassen. Dieser Code enthält nichts, was eine Ausnahme für geschlossene oder unterbrochene Rohre verursachen würde.PipedInputStream
Javadocs gesehen: Eine Pipe wird als unterbrochen bezeichnet, wenn ein Thread, der Datenbytes für den verbundenen Pipeline-Ausgabestream bereitstellt, nicht mehr aktiv ist. Ich vermute also, dass der Thread abgeschlossen ist, wenn Sie das obige Beispiel verwenden, bevorJax-RS
der Eingabestream verbraucht wird. Gleichzeitig habe ich mir die MongoDB Javadocs angesehen.GridFSDBFile
hat einen Eingabestream, warum also nicht einfach an Jax-RS weitergeben ?Da Eingabe- und Ausgabestreams nur Start- und Endpunkt sind, besteht die Lösung darin, Daten vorübergehend in einem Byte-Array zu speichern. Sie müssen also ein Zwischenprodukt erstellen
ByteArrayOutputStream
, aus dem Sie ein Zwischenprodukt erstellenbyte[]
, das als Eingabe für new verwendet wirdByteArrayInputStream
.Ich hoffe es hilft.
quelle
Sie benötigen eine Zwischenklasse, die zwischen puffert. Bei jedem
InputStream.read(byte[]...)
Aufruf füllt die Pufferklasse das übergebene Byte-Array mit dem nächsten übergebenen Block vonOutputStream.write(byte[]...)
. Da die Größe der Chunks möglicherweise nicht gleich ist, muss die Adapterklasse eine bestimmte Menge speichern, bis sie genug hat, um den Lesepuffer zu füllen und / oder einen Pufferüberlauf speichern zu können.Dieser Artikel enthält eine schöne Aufschlüsselung einiger verschiedener Ansätze für dieses Problem:
http://blog.ostermiller.org/convert-java-outputstream-inputstream
quelle
quelle
toByteArray()
Methodenkörper wie folgtreturn Arrays.copyOf(buf, count);
aussieht und ein neues Array zurückgibt.Die easystream Open Source-Bibliothek unterstützt direkt die Konvertierung eines OutputStream in einen InputStream: http://io-tools.sourceforge.net/easystream/tutorial/tutorial.html
Sie listen auch andere Optionen auf: http://io-tools.sourceforge.net/easystream/OutputStream_to_InputStream.html
quelle
Ich bin auf das gleiche Problem bei der Konvertierung von a
ByteArrayOutputStream
in a gestoßenByteArrayInputStream
und habe es mithilfe einer abgeleiteten Klasse gelöst, von derByteArrayOutputStream
a zurückgegeben werden kannByteArrayInputStream
, die mit dem internen Puffer von initialisiert wurdeByteArrayOutputStream
. Auf diese Weise wird kein zusätzlicher Speicher verwendet und die 'Konvertierung' ist sehr schnell:Ich habe das Zeug auf Github gestellt: https://github.com/nickrussler/ByteArrayInOutStream
quelle
Die io-Extras der Bibliothek können nützlich sein. Zum Beispiel, wenn Sie eine
InputStream
VerwendungGZIPOutputStream
gzipen möchten und möchten, dass sie synchron erfolgt (unter Verwendung der Standardpuffergröße von 8192):Beachten Sie, dass die Bibliothek zu 100% über Unit-Tests verfügt (was das natürlich wert ist!) Und sich in Maven Central befindet. Die Maven-Abhängigkeit ist:
Achten Sie darauf, nach einer späteren Version zu suchen.
quelle
Aus meiner Sicht ist java.io.PipedInputStream / java.io.PipedOutputStream die beste Option. In einigen Situationen möchten Sie möglicherweise ByteArrayInputStream / ByteArrayOutputStream verwenden. Das Problem ist, dass Sie den Puffer duplizieren müssen, um einen ByteArrayOutputStream in einen ByteArrayInputStream zu konvertieren. Auch ByteArrayOutpuStream / ByteArrayInputStream sind auf 2 GB beschränkt. Hier ist eine OutpuStream / InputStream-Implementierung, die ich geschrieben habe, um die Einschränkungen von ByteArrayOutputStream / ByteArrayInputStream zu umgehen (Scala-Code, aber für Java-Entwickler leicht verständlich):
Einfach zu bedienen, keine Pufferduplizierung, keine Speicherbeschränkung von 2 GB
quelle
Wenn Sie einen OutputStream aus einem InputStream erstellen möchten, gibt es ein grundlegendes Problem. Eine Methode, die in einen OutputStream schreibt, blockiert, bis dies abgeschlossen ist. Das Ergebnis ist also verfügbar, wenn die Schreibmethode abgeschlossen ist. Dies hat zwei Konsequenzen:
Variante 1 kann mit Byte-Arrays implementiert oder abgelegt werden. Variante 1 kann mithilfe von Pipies implementiert werden (entweder direkt oder mit zusätzlicher Abstraktion - z. B. RingBuffer oder die Google-Bibliothek aus dem anderen Kommentar).
In der Tat gibt es mit Standard-Java keinen anderen Weg, um das Problem zu lösen. Jede Lösung ist eine Implementierung einer dieser Lösungen.
Es gibt ein Konzept namens "Fortsetzung" (siehe Wikipedia für Details). In diesem Fall bedeutet dies im Grunde:
Während in einigen Sprachen dieses Konzept integriert ist, benötigen Sie für Java etwas "Magie". Zum Beispiel implementiert "commons-javaflow" von Apache solche für Java. Der Nachteil ist, dass dies einige spezielle Bytecode-Änderungen zur Erstellungszeit erfordert. Es wäre also sinnvoll, das gesamte Material mit benutzerdefinierten Build-Skripten in eine zusätzliche Bibliothek zu stellen.
quelle
Alter Beitrag, könnte aber anderen helfen. Verwenden Sie diesen Weg:
quelle
toString().getBytes()
eines Streams * der Inhalt des Streams nicht zurückgegeben.Obwohl Sie einen OutputStream nicht in einen InputStream konvertieren können, bietet Java mithilfe von PipedOutputStream und PipedInputStream eine Möglichkeit, Daten in einen PipedOutputStream schreiben zu lassen, um über einen zugeordneten PipedInputStream verfügbar zu werden.
Vor einiger Zeit sah ich mich einer ähnlichen Situation gegenüber, als ich mich mit Bibliotheken von Drittanbietern befasste, bei denen anstelle einer OutputStream-Instanz eine InputStream-Instanz an diese übergeben werden musste.
Ich habe dieses Problem behoben, indem ich PipedInputStream und PipedOutputStream verwendet habe.
Übrigens sind sie schwierig zu bedienen und Sie müssen Multithreading verwenden, um das zu erreichen, was Sie wollen. Ich habe kürzlich eine Implementierung auf Github veröffentlicht, die Sie verwenden können.
Hier ist der Link . Sie können das Wiki durchgehen, um zu verstehen, wie man es benutzt.
quelle