Esta página: http://blog.ostermiller.org/convert-java-outputstream-inputstream describe cómo crear un InputStream desde OutputStream:
new ByteArrayInputStream(out.toByteArray())
Otras alternativas son usar PipedStreams y nuevos hilos, lo cual es engorroso.
No me gusta la idea de copiar muchos megabytes en una nueva matriz de bytes de memoria. ¿Existe una biblioteca que haga esto de manera más eficiente?
EDITAR:
Siguiendo el consejo de Laurence Gonsalves, probé PipedStreams y resultó que no son tan difíciles de manejar. Aquí está el código de muestra en clojure:
(defn #^PipedInputStream create-pdf-stream [pdf-info]
(let [in-stream (new PipedInputStream)
out-stream (PipedOutputStream. in-stream)]
(.start (Thread. #(;Here you write into out-stream)))
in-stream))
fuente
new Thread
no es apropiado en su contenedor por cualquier motivo, entonces vea si hay un grupo de subprocesos que pueda usar.Hay otra biblioteca de código abierto llamada EasyStream que se ocupa de las tuberías y los hilos de forma transparente. Eso no es complicado si todo va bien. Los problemas surgen cuando (mirando el ejemplo de Laurence Gonsalves)
Lanza una excepción. En ese ejemplo, el hilo simplemente se completa y la excepción se pierde, mientras que el exterior
InputStream
podría truncarse.Easystream se ocupa de la propagación de excepciones y otros problemas desagradables que he estado depurando durante aproximadamente un año. (Soy el encargado de la biblioteca: obviamente mi solución es la mejor;)) Aquí hay un ejemplo de cómo usarla:
final InputStreamFromOutputStream<String> isos = new InputStreamFromOutputStream<String>(){ @Override public String produce(final OutputStream dataSink) throws Exception { /* * call your application function who produces the data here * WARNING: we're in another thread here, so this method shouldn't * write any class field or make assumptions on the state of the outer class. */ return produceMydata(dataSink) } };
También hay una buena introducción donde se explican todas las otras formas de convertir un OutputStream en un InputStream. Vale la pena echarle un vistazo.
fuente
Una solución simple que evita copiar el búfer es crear un propósito especial
ByteArrayOutputStream
:public class CopyStream extends ByteArrayOutputStream { public CopyStream(int size) { super(size); } /** * Get an input stream based on the contents of this output stream. * Do not use the output stream after calling this method. * @return an {@link InputStream} */ public InputStream toInputStream() { return new ByteArrayInputStream(this.buf, 0, this.count); } }
Escriba en el flujo de salida anterior según sea necesario, luego llame
toInputStream
para obtener un flujo de entrada sobre el búfer subyacente. Considere el flujo de salida como cerrado después de ese punto.fuente
Creo que la mejor manera de conectar InputStream a OutputStream es a través de flujos canalizados , disponibles en el paquete java.io, de la siguiente manera:
// 1- Define stream buffer private static final int PIPE_BUFFER = 2048; // 2 -Create PipedInputStream with the buffer public PipedInputStream inPipe = new PipedInputStream(PIPE_BUFFER); // 3 -Create PipedOutputStream and bound it to the PipedInputStream object public PipedOutputStream outPipe = new PipedOutputStream(inPipe); // 4- PipedOutputStream is an OutputStream, So you can write data to it // in any way suitable to your data. for example: while (Condition) { outPipe.write(mByte); } /*Congratulations:D. Step 4 will write data to the PipedOutputStream which is bound to the PipedInputStream so after filling the buffer this data is available in the inPipe Object. Start reading it to clear the buffer to be filled again by the PipedInputStream object.*/
En mi opinión, hay dos ventajas principales para este código:
1 - No hay consumo adicional de memoria a excepción del búfer.
2 - No necesita manejar la cola de datos manualmente
fuente
Por lo general, trato de evitar la creación de un subproceso separado debido a la mayor posibilidad de interbloqueo, la mayor dificultad para comprender el código y los problemas de lidiar con excepciones.
Aquí está mi solución propuesta: un ProducerInputStream que crea contenido en fragmentos mediante llamadas repetidas a produceChunk ():
public abstract class ProducerInputStream extends InputStream { private ByteArrayInputStream bin = new ByteArrayInputStream(new byte[0]); private ByteArrayOutputStream bout = new ByteArrayOutputStream(); @Override public int read() throws IOException { int result = bin.read(); while ((result == -1) && newChunk()) { result = bin.read(); } return result; } @Override public int read(byte[] b, int off, int len) throws IOException { int result = bin.read(b, off, len); while ((result == -1) && newChunk()) { result = bin.read(b, off, len); } return result; } private boolean newChunk() { bout.reset(); produceChunk(bout); bin = new ByteArrayInputStream(bout.toByteArray()); return (bout.size() > 0); } public abstract void produceChunk(OutputStream out); }
fuente