¿Cómo convierto un OutputStream en un InputStream?

Resuelto Waypoint asked hace 13 años • 14 respuestas

Estoy en la etapa de desarrollo donde tengo dos módulos y de uno obtuve el resultado como OutputStream, y el segundo que acepta solo InputStream.

¿Sabes cómo convertir OutputStreama InputStream(no al revés, quiero decir realmente de esta manera) para poder conectar estas dos partes?

Waypoint avatar Apr 25 '11 20:04 Waypoint
Aceptado

Parece haber muchos enlaces y otras cosas similares, pero ningún código real que utilice tuberías. La ventaja de utilizar java.io.PipedInputStreamy java.io.PipedOutputStreames que no hay consumo adicional de memoria. ByteArrayOutputStream.toByteArray()devuelve una copia del búfer original, lo que significa que lo que sea que tengas en la memoria, ahora tienes dos copias. Luego, escribir en un InputStreamsignifica que ahora tiene tres copias de los datos.

El código que usa lambdas(sombrero para @John Manko de los comentarios):

PipedInputStream in = new PipedInputStream();
final PipedOutputStream out = new PipedOutputStream(in);
// in a background thread, write the given output stream to the
// PipedOutputStream for consumption
new Thread(() -> {originalOutputStream.writeTo(out);}).start();

Una cosa que @John Manko notó es que en ciertos casos, cuando no tienes control de la creación de OutputStream , puedes terminar en una situación en la que el creador puede limpiar el objeto OutputStream prematuramente. Si obtienes el ClosedPipeException, deberías intentar invertir los constructores:

PipedInputStream in = new PipedInputStream(out);
new Thread(() -> {originalOutputStream.writeTo(out);}).start();

Tenga en cuenta que también puede invertir los constructores de los ejemplos siguientes.

Gracias también a @AlexK por corregirme al iniciar un Threaden lugar de simplemente iniciar un Runnable.


El código usando try-with-resources:

// take the copy of the stream and re-write it to an InputStream
PipedInputStream in = new PipedInputStream();
    new Thread(new Runnable() {
        public void run () {
            // try-with-resources here
            // putting the try block outside the Thread will cause the
            // PipedOutputStream resource to close before the Runnable finishes
            try (final PipedOutputStream out = new PipedOutputStream(in)) {
                // write the original OutputStream to the PipedOutputStream
                // note that in order for the below method to work, you need
                // to ensure that the data has finished writing to the
                // ByteArrayOutputStream
                originalByteArrayOutputStream.writeTo(out);
            }
            catch (IOException e) {
                // logging and exception handling should go here
            }
        }
    }).start();

El código original que escribí:

// take the copy of the stream and re-write it to an InputStream
PipedInputStream in = new PipedInputStream();
final PipedOutputStream out = new PipedOutputStream(in);
new Thread(new Runnable() {
    public void run () {
        try {
            // write the original OutputStream to the PipedOutputStream
            // note that in order for the below method to work, you need
            // to ensure that the data has finished writing to the
            // ByteArrayOutputStream
            originalByteArrayOutputStream.writeTo(out);
        }
        catch (IOException e) {
            // logging and exception handling should go here
        }
        finally {
            // close the PipedOutputStream here because we're done writing data
            // once this thread has completed its run
            if (out != null) {
                // close the PipedOutputStream cleanly
                out.close();
            }
        }   
    }
}).start();

Este código supone que originalByteArrayOutputStream es un, ByteArrayOutputStreamya que suele ser el único flujo de salida utilizable, a menos que esté escribiendo en un archivo. Lo mejor de esto es que, dado que está en un hilo separado, también funciona en paralelo, por lo que cualquier cosa que consuma su flujo de entrada también saldrá de su antiguo flujo de salida. Esto es beneficioso porque el búfer puede permanecer más pequeño y tendrá menos latencia y menos uso de memoria.

Si no tiene un ByteArrayOutputStream, en lugar de usarlo writeTo(), tendrá que usar uno de los write()métodos de la java.io.OutputStreamclase o uno de los otros métodos disponibles en una subclase.

mikeho avatar May 26 '2014 16:05 mikeho

An OutputStreames aquel en el que escribes datos. Si algún módulo expone un OutputStream, la expectativa es que haya algo leyendo en el otro extremo.

Algo que expone un InputStream, por otro lado, indica que necesitarás escuchar esta transmisión y habrá datos que podrás leer.

Entonces es posible conectar un InputStreama unOutputStream

InputStream----read---> intermediateBytes[n] ----write----> OutputStream

Como alguien mencionó, esto es lo que le permite hacer el copy()método de IOUtils . No tiene sentido ir al otro lado... ojalá esto tenga algún sentido.

ACTUALIZAR:

Por supuesto, cuanto más pienso en esto, más puedo ver cómo en realidad sería un requisito. Sé que algunos de los comentarios mencionaron Pipedflujos de entrada/salida, pero existe otra posibilidad.

Si el flujo de salida expuesto es ByteArrayOutputStream, siempre puede obtener el contenido completo llamando al toByteArray()método. Luego puede crear un contenedor de flujo de entrada utilizando la ByteArrayInputStreamsubclase. Estos dos son pseudo-flujos, básicamente ambos simplemente envuelven una matriz de bytes. Por lo tanto, utilizar los streams de esta manera es técnicamente posible, pero para mí sigue siendo muy extraño...

Java Drinker avatar Apr 25 '2011 13:04 Java Drinker

Como los flujos de entrada y salida son solo puntos de inicio y finalización, la solución es almacenar datos temporalmente en una matriz de bytes. Por lo tanto, debe crear un intermedio ByteArrayOutputStream, a partir del cual crea byte[]y que se utiliza como entrada para el nuevo ByteArrayInputStream.

public void doTwoThingsWithStream(InputStream inStream, OutputStream outStream){ 
  //create temporary bayte array output stream
  ByteArrayOutputStream baos = new ByteArrayOutputStream();
  doFirstThing(inStream, baos);
  //create input stream from baos
  InputStream isFromFirstData = new ByteArrayInputStream(baos.toByteArray()); 
  doSecondThing(isFromFirstData, outStream);
}

Espero eso ayude.

BorutT avatar May 08 '2014 08:05 BorutT
ByteArrayOutputStream buffer = (ByteArrayOutputStream) aOutputStream;
byte[] bytes = buffer.toByteArray();
InputStream inputStream = new ByteArrayInputStream(bytes);
Vijay avatar Jan 27 '2017 07:01 Vijay