web-dev-qa-db-fra.com

Comment fermer un flux lisible (avant la fin)?

Comment fermer un flux lisible dans Node.js?

var input = fs.createReadStream('lines.txt');

input.on('data', function(data) {
   // after closing the stream, this will not
   // be called again

   if (gotFirstLine) {
      // close this stream and continue the
      // instructions from this if
      console.log("Closed.");
   }
});

Ce serait mieux que:

input.on('data', function(data) {
   if (isEnded) { return; }

   if (gotFirstLine) {
      isEnded = true;
      console.log("Closed.");
   }
});

Mais cela n'arrêterait pas le processus de lecture ...

76
Ionică Bizău

Invoquez input.close(). Ce n'est pas dans la documentation, mais

https://github.com/joyent/node/blob/cfcb1de130867197cbc9c6012b7e84e08e53d032/lib/fs.js#L1597-L162

fait clairement le travail :) Il fait en fait quelque chose de similaire à votre isEnded.

EDITER 2015-avr-19 Basé sur les commentaires ci-dessous, et pour clarifier et mettre à jour:

  • Cette suggestion est un hack et n'est pas documentée.
  • Bien que pour regarder le lib/fs.js Actuel, il fonctionne toujours> 1,5 ans plus tard.
  • Je suis d'accord avec le commentaire ci-dessous sur l'appel de destroy() étant préférable.
  • Comme indiqué correctement ci-dessous, cela fonctionne pour fsReadStreams, pas sur un générique Readable.

En ce qui concerne une solution générique: il ne semble pas qu'il en existe une, du moins d'après ma compréhension de la documentation et d'après un rapide coup d'œil à _stream_readable.js.

Ma proposition mettrait votre flux lisible en mode en pause, empêchant au moins tout traitement ultérieur dans votre source de données en amont. N'oubliez pas de unpipe() et supprimez tous les écouteurs d'événement data afin que pause() s'interrompt réellement, comme indiqué dans la documentation

29
Nitzan Shaked

Edit: Bonne nouvelle! Commençant par Node.js 8.0.0 readable.destroy est officiellement disponible: https://nodejs.org/api/stream.html#stream_readable_destroy_error

ReadStream.destroy

Vous pouvez appeler la fonction ReadStream.destroy à tout moment.

var fs = require('fs');

var readStream = fs.createReadStream('lines.txt');
readStream
    .on('data', function (chunk) {
        console.log(chunk);
        readStream.destroy();
    })
    .on('end', function () {
        // This may not been called since we are destroying the stream
        // the first time 'data' event is received
        console.log('All the data in the file has been read');
    })
    .on('close', function (err) {
        console.log('Stream has been destroyed and file has been closed');
    });

La fonction publique ReadStream.destroy n'est pas documenté (Node.js v0.12.2) mais vous pouvez consulter le code source sur GitHub ( commit du 5 octobre 2012 ).

La fonction destroy marque en interne l'instance ReadStream comme détruite et appelle la fonction close pour libérer le fichier.

Vous pouvez écouter le événement de fermeture pour savoir exactement quand le fichier est fermé. Le événement final ne se déclenchera que si les données sont complètement consommées.


Notez que les fonctions destroy (et close) sont spécifiques à fs.ReadStream . Il ne fait pas partie du générique stream.readable "interface".

54
Yves M.

Aujourd'hui, dans Node 10

readableStream.destroy()

est le moyen officiel de fermer un flux lisible

voir https://nodejs.org/api/stream.html#stream_readable_destroy_error

17
Jo-Go

Tu ne peux pas. Il n’existe aucun moyen documenté de fermer/arrêter/abandonner/détruire un flux générique Lisible à partir de Node 5.3.0. Il s’agit d’une limitation du Node architecture de flux.

Comme d'autres réponses l'ont expliqué, il existe des méthodes informelles pour des implémentations spécifiques de Readable fournies par Node, telles que fs.ReadStream . Ce ne sont pas des solutions génériques pour tout lisible cependant.

Si quelqu'un peut me prouver le contraire, faites-le. Je voudrais pouvoir faire ce que je dis est impossible, et serais ravi d'être corrigé.

[~ # ~] edit [~ # ~] : Voici ma solution de contournement: implémenter .destroy() pour mon pipeline bien qu'une série complexe de unpipe() appelle. Et après toute cette complexité, cela ne fonctionne pas correctement dans tous les cas .

[~ # ~] éditer [~ # ~] : Node v8.0.0 ajouté un destroy() api pour les flux lisibles .

11
thejoshwolfe

À la version 4.*.* l'insertion d'une valeur nulle dans le flux déclenchera un signal EOF.

De la documentation de nodejs

Si une valeur autre que null est transmise, la méthode Push () ajoute un bloc de données à la file d'attente pour que les processeurs de flux ultérieurs l'utilisent. Si null est passé, il signale la fin du flux (EOF), après quoi aucune autre donnée ne peut être écrite.

Cela a fonctionné pour moi après avoir essayé de nombreuses autres options sur cette page.

10
Jacob Lowe

Ce module destroy est destiné à assurer la destruction d’un flux de données, en traitant différentes API et bogues Node.js. En ce moment est l'un des meilleurs choix.

NB. À partir de Node 10, vous pouvez utiliser le .destroy méthode sans autres dépendances.

5
Rocco Musolino

C'est une vieille question, mais moi aussi je cherchais la réponse et j'ai trouvé la meilleure pour ma mise en œuvre. Les deux événements end et close sont émis, alors je pense que c'est la solution la plus propre.

Cela fera l'affaire dans le noeud 4.4. * (Version stable au moment de l'écriture):

var input = fs.createReadStream('lines.txt');

input.on('data', function(data) {
   if (gotFirstLine) {
      this.end(); // Simple isn't it?
      console.log("Closed.");
   }
});

Pour une explication très détaillée, voir: http://www.bennadel.com/blog/2692-you-have-to-explicitly-end-streams-after-pipes-break-in-node-js.htm

3
Vexter

Vous pouvez effacer et fermer le flux avec yourstream.resume(), qui videra tout le contenu du flux et le fermera éventuellement.

De la document officiel :

readable.resume ():

Retour: ceci

Cette méthode fera en sorte que le flux lisible recommence à émettre des événements 'data'.

Cette méthode basculera le flux en mode fluide. Si vous ne souhaitez pas utiliser les données d'un flux, mais souhaitez accéder à son événement 'end', vous pouvez appeler stream.resume () pour ouvrir le flux de données.

var readable = getReadableStreamSomehow();
readable.resume();
readable.on('end', () => {
  console.log('got to the end, but did not read anything');
});
3
Sayem

Ce code va faire l'affaire ici:

function closeReadStream(stream) {
    if (!stream) return;
    if (stream.close) stream.close();
    else if (stream.destroy) stream.destroy();
}

writeStream.end () est le moyen idéal de fermer un writeStream ...

2
g00dnatur3