Pergunta

Nesta página: http://blog.ostermiller.org/convert-java-outputstream-inputstream descreve como criar um InputStream do OutputStream:

new ByteArrayInputStream(out.toByteArray())

Outras alternativas são o uso PipedStreams e novos threads que é complicado.

Eu não gosto da idéia de copiar muitos megabytes de novo na memória matriz de bytes.Existe uma biblioteca que faz isso de forma mais eficiente?

EDITAR:

Por assessoria de Laurence Gonsalves, eu tentei PipedStreams e acabou que eles não são difíceis de lidar.Aqui está o exemplo de código em 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))
Foi útil?

Solução

Se você não deseja copiar todos os dados em um buffer na memória de uma vez, terá que ter seu código que use o outputStream (o produtor) e o código que usa o InputStream (o consumidor ) alterne no mesmo encadeamento ou opere simultaneamente em dois threads separados. Tê -los operando no mesmo segmento provavelmente é muito mais complicado que o uso de dois threads separados é muito mais propenso a erros (você precisará garantir que o consumidor Nunca blocos aguardando a entrada, ou você efetivamente o impasse) e exigiria que o produtor e o consumidor funcionassem no mesmo loop, o que parece muito bem acoplado.

Portanto, use um segundo tópico. Realmente não é tão complicado. A página para a qual você vinculou teve um exemplo perfeito:

  PipedInputStream in = new PipedInputStream();
  PipedOutputStream out = new PipedOutputStream(in);
  new Thread(
    new Runnable(){
      public void run(){
        class1.putDataOnOutputStream(out);
      }
    }
  ).start();
  class2.processDataFromInputStream(in);

Outras dicas

Há uma outra biblioteca de código Aberto chamado EasyStream que lida com tubos de thread e de uma forma transparente.Que não é realmente complicado, se tudo correr bem.Os problemas surgem quando (olhando Laurence Gonsalves exemplo)

aula1.putDataOnOutputStream(out);

Lança uma exceção.Nesse exemplo, a thread simplesmente completa e a exceção é perdido, enquanto o exterior InputStream pode ser truncado.

Easystream lida com a propagação de exceção e de outros problemas desagradáveis que eu tenho de depuração durante cerca de um ano.(Eu tenho a versão cvs atual da biblioteca:obviamente, a minha solução é a melhor ;) ) Aqui está um exemplo de como usá-lo:

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)
 }
};

Existe também um agradável introdução onde todas as outras formas de converter um OutputStream em um InputStream são explicados.Vale a pena dar uma olhada.

Uma solução simples que evita copiar o buffer é criar um uso 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);
    }
}

Escreva para o fluxo de saída acima, conforme necessário, depois ligue toInputStream Para obter um fluxo de entrada sobre o buffer subjacente. Considere o fluxo de saída fechado após esse ponto.

Eu acho fluxos canalizados - Disponível no pacote java.io, como segue:

// 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.*/

Na minha opinião, existem duas vantagens principais para este código:

1 - Não há consumo adicional de memória, exceto o buffer.

2 - Você não precisa lidar com a fila de dados manualmente

Normalmente, tento evitar a criação de um tópico separado devido à maior chance de impasse, ao aumento da dificuldade de entender o código e os problemas de lidar com exceções.

Aqui está minha solução proposta: um produtorInputStream que cria conteúdo em pedaços por chamadas repetidas para ProduckUnk ():

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);

}
Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top