Question

Cette page: http://blog.ostermiller.org/convert-java-outputstream -inputstream décrit comment créer un InputStream à partir de OutputStream:

new ByteArrayInputStream(out.toByteArray())

Une autre solution consiste à utiliser PipedStreams et de nouveaux threads, ce qui est fastidieux.

Je n’aime pas l’idée de copier plusieurs mégaoctets dans un nouveau tableau d’octets mémoire. Y a-t-il une bibliothèque qui le fait plus efficacement?

EDIT:

Sur les conseils de Laurence Gonsalves, j’ai essayé PipedStreams et il s’est avéré qu’ils ne sont pas si difficiles à gérer. Voici l'exemple de code dans 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))
Était-ce utile?

La solution

Si vous ne voulez pas copier toutes les données dans un tampon en mémoire en même temps, votre code utilisant OutputStream (le producteur) et le code utilisant InputStream devront être insérés. (le consommateur) alterne dans le même thread ou opère simultanément dans deux threads distincts. Les faire fonctionner dans le même thread est probablement beaucoup plus compliqué que d'utiliser deux threads séparés, c'est beaucoup plus sujet aux erreurs (vous devrez vous assurer que le consommateur jamais bloque l'attente d'entrée ou que vous ' Il s’agirait effectivement d’une impasse) et nécessiterait que le producteur et le consommateur se retrouvent dans la même boucle, ce qui semble bien trop couplé.

Utilisez donc un deuxième thread. Ce n'est vraiment pas si compliqué. La page que vous avez liée avait un exemple parfait:

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

Autres conseils

Il existe une autre bibliothèque Open Source appelée EasyStream qui traite les tuyaux et le filetage de manière transparente. Ce n'est pas vraiment compliqué si tout se passe bien. Des problèmes surviennent lorsque (en regardant l'exemple de Laurence Gonsalves)

  

class1.putDataOnOutputStream (out);

Lance une exception. Dans cet exemple, le thread se termine simplement et l'exception est perdue, tandis que le InputStream extérieur peut être tronqué.

Easystream traite de la propagation des exceptions et d’autres problèmes graves que je corrige depuis environ un an. (Je suis le responsable de la bibliothèque: évidemment ma solution est la meilleure;)) Voici un exemple d'utilisation:

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

Il existe également une agréable introduction , où tous les autres moyens de convertir un OutputStream dans un InputStream sont expliqués. Cela vaut le coup d'oeil.

Une solution simple qui évite de copier le tampon consiste à créer un 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);
    }
}

Ecrivez si nécessaire dans le flux de sortie ci-dessus, puis appelez toInputStream pour obtenir un flux d'entrée sur le tampon sous-jacent. Considérez le flux de sortie comme fermé après ce point.

Je pense que le meilleur moyen de connecter InputStream à un OutputStream consiste à flux acheminés - disponible dans le package java.io, comme suit:

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

À mon avis, ce code présente deux avantages principaux:

1 - Il n'y a pas de consommation supplémentaire de mémoire à l'exception du tampon.

2 - Vous n'avez pas besoin de gérer manuellement la mise en file d'attente des données

J'essaie généralement d'éviter de créer un thread séparé en raison du risque accru de blocage, de la difficulté accrue à comprendre le code et des problèmes de gestion des exceptions.

Voici ma solution proposée: un ProducerInputStream qui crée du contenu en morceaux par des appels répétés à productChunk ():

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

}
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top