102 votes

Node.js Piping the same readable stream into multiple (writable) targets

J'ai besoin d'exécuter deux commandes en série qui doivent lire des données à partir du même flux. Après avoir redirigé un flux dans un autre, le tampon est vidé, donc je ne peux pas lire à nouveau des données à partir de ce flux, donc cela ne fonctionne pas :

var spawn = require('child_process').spawn;
var fs = require('fs');
var request = require('request');

var inputStream = request('http://placehold.it/640x360');
var identify = spawn('identify',['-']);

inputStream.pipe(identify.stdin);

var chunks = [];
identify.stdout.on('data',function(chunk) {
  chunks.push(chunk);
});

identify.stdout.on('end',function() {
  var size = getSize(Buffer.concat(chunks)); //width
  var convert = spawn('convert',['-','-scale',size * 0.5,'png:-']);
  inputStream.pipe(convert.stdin);
  convert.stdout.pipe(fs.createWriteStream('half.png'));
});

function getSize(buffer){
  return parseInt(buffer.toString().split(' ')[2].split('x')[0]);
}

Request se plaint de cela

Erreur : Vous ne pouvez pas rediriger après que des données aient été émises de la réponse.

et changer le inputStream en fs.createWriteStream entraîne bien sûr le même problème. Je ne veux pas écrire dans un fichier mais réutiliser en quelque sorte le flux que request produit (ou tout autre d'ailleurs).

Existe-t-il un moyen de réutiliser un flux lisible une fois qu'il a fini d'être redirigé ? Quel serait le meilleur moyen d'accomplir quelque chose comme l'exemple ci-dessus ?

1voto

Zied Hamdi Points 877

J'ai une solution différente pour écrire sur deux flux simultanément, naturellement, le temps d'écriture sera l'addition des deux temps, mais je l'utilise pour répondre à une demande de téléchargement, où je veux conserver une copie du fichier téléchargé sur mon serveur (en fait j'utilise une sauvegarde S3, donc je mets en cache les fichiers les plus utilisés localement pour éviter les transferts de fichiers multiples)

/**
 * Une classe utilitaire conçue pour écrire dans un fichier tout en répondant à une demande de téléchargement de fichier
 */
class TwoOutputStreams {
  constructor(streamOne, streamTwo) {
    this.streamOne = streamOne
    this.streamTwo = streamTwo
  }

  setHeader(header, value) {
    if (this.streamOne.setHeader)
      this.streamOne.setHeader(header, value)
    if (this.streamTwo.setHeader)
      this.streamTwo.setHeader(header, value)
  }

  write(chunk) {
    this.streamOne.write(chunk)
    this.streamTwo.write(chunk)
  }

  end() {
    this.streamOne.end()
    this.streamTwo.end()
  }
}

Vous pouvez alors utiliser ceci comme un OutputStream normal

const twoStreamsOut = new TwoOutputStreams(fileOut, responseStream)

et le passer à votre méthode comme s'il s'agissait d'une réponse ou d'un fileOutputStream

-1voto

user3683370 Points 25

Que diriez-vous de rediriger vers deux flux ou plus, mais pas en même temps ?

Par exemple :

var PassThrough = require('stream').PassThrough;
var mybiraryStream = stream.start(); //flux audio infini
var file1 = fs.createWriteStream('file1.wav',{encoding:'binary'})
var file2 = fs.createWriteStream('file2.wav',{encoding:'binary'})
var mypass = PassThrough
mybinaryStream.pipe(mypass)
mypass.pipe(file1)
setTimeout(function(){
   mypass.pipe(file2);
},2000)

Le code ci-dessus ne génère aucune erreur mais le fichier2 est vide

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X