web-dev-qa-db-fra.com

Comment créer des flux à partir de chaîne dans Node.Js?

J'utilise une bibliothèque, ya-csv , qui attend un fichier ou un flux en entrée, mais j'ai une chaîne.

Comment convertir cette chaîne en un flux dans Node?

149
pathikrit

Comme @ substack m'a corrigé dans # noeud , la nouvelle API de flux dans Node v10 facilite ceci:

const Readable = require('stream').Readable;
const s = new Readable();
s._read = () => {}; // redundant? see update below
s.Push('your text here');
s.Push(null);

… Après quoi vous pouvez librement pipe ou bien le transmettre au consommateur auquel vous êtes destiné.

Ce n'est pas aussi propre que le resumer one-liner, mais cela évite la dépendance supplémentaire.

( Mise à jour: jusqu'à présent dans les versions v.10.10.26 à 9.2.1, un appel à Push directement à partir du fichier REPL L'invite se plantera avec une exception not implemented si vous n'avez pas défini _read. Elle ne plantera pas dans une fonction ou un script. Si une incohérence vous rend nerveux, incluez le noop.)

165
Garth Kidd

N'utilisez pas la réponse de client de Jo Liss. Cela fonctionnera dans la plupart des cas, mais dans mon cas, cela m'a fait perdre 4 ou 5 heures de recherche de bogues. Ce n'est pas nécessaire pour les modules tiers.

NOUVELLE RÉPONSE :

var Readable = require('stream').Readable

var s = new Readable
s.Push('beep')    // the string you want
s.Push(null)      // indicates end-of-file basically - the end of the stream

Cela devrait être un flux entièrement compatible Lisible. Voir ici pour plus d'informations sur l'utilisation correcte des flux.

ANCIENNE REPONSE : utilisez simplement le flux natif PassThrough:

var stream = require("stream")
var a = new stream.PassThrough()
a.write("your string")
a.end()

a.pipe(process.stdout) // piping will work as normal
/*stream.on('data', function(x) {
   // using the 'data' event works too
   console.log('data '+x)
})*/
/*setTimeout(function() {
   // you can even pipe after the scheduler has had time to do other things
   a.pipe(process.stdout) 
},100)*/

a.on('end', function() {
    console.log('ended') // the end event will be called properly
})

Notez que l'événement 'close' n'est pas émis (ce qui n'est pas requis par les interfaces de flux).

105
B T

Créez simplement une nouvelle instance du module stream et personnalisez-la en fonction de vos besoins:

var Stream = require('stream');
var stream = new Stream();

stream.pipe = function(dest) {
  dest.write('your string');
  return dest;
};

stream.pipe(process.stdout); // in this case the terminal, change to ya-csv

ou

var Stream = require('stream');
var stream = new Stream();

stream.on('data', function(data) {
  process.stdout.write(data); // change process.stdout to ya-csv
});

stream.emit('data', 'this is my string');
28
zemirco

Edit: La réponse de Garth est probablement meilleur.

Mon ancien texte de réponse est conservé ci-dessous.


Pour convertir une chaîne en flux, vous pouvez utiliser un flux en pause à travers :

through().pause().queue('your string').end()

Exemple:

var through = require('through')

// Create a paused stream and buffer some data into it:
var stream = through().pause().queue('your string').end()

// Pass stream around:
callback(null, stream)

// Now that a consumer has attached, remember to resume the stream:
stream.resume()
12
Jo Liss

Il existe un module pour cela: https://www.npmjs.com/package/string-to-stream

var str = require('string-to-stream')
str('hi there').pipe(process.stdout) // => 'hi there' 
10
Lori

Une autre solution est de passer la fonction de lecture au constructeur de Readable (cf doc options de lecture de flux )

var s = new Readable({read(size) {
    this.Push("your string here")
    this.Push(null)
  }});

vous pouvez utiliser par exemple le tuyau par exemple

6
Philippe T.

en café-script:

class StringStream extends Readable
  constructor: (@str) ->
    super()

  _read: (size) ->
    @Push @str
    @Push null

utilise le:

new StringStream('text here').pipe(stream1).pipe(stream2)
6
xinthink

J'étais fatiguée de devoir réapprendre cela tous les six mois, alors je viens de publier un module npm pour résumer les détails de la mise en œuvre:

https://www.npmjs.com/package/streamify-string

C'est le coeur du module:

const Readable = require('stream').Readable;
const util     = require('util');

function Streamify(str, options) {

  if (! (this instanceof Streamify)) {
    return new Streamify(str, options);
  }

  Readable.call(this, options);
  this.str = str;
}

util.inherits(Streamify, Readable);

Streamify.prototype._read = function (size) {

  var chunk = this.str.slice(0, size);

  if (chunk) {
    this.str = this.str.slice(size);
    this.Push(chunk);
  }

  else {
    this.Push(null);
  }

};

module.exports = Streamify;

str est la string qui doit être transmise au constructeur lors de l'appel, et sera transmise par le flux en tant que données. options sont les options typiques pouvant être transmises à un flux, par la documentation .

Selon Travis CI, il devrait être compatible avec la plupart des versions de noeud.

5
Chris Allen Lane

Voici une solution simple dans TypeScript:

import { Readable } from 'stream'

class ReadableString extends Readable {
    private sent = false

    constructor(
        private str: string
    ) {
        super();
    }

    _read() {
        if (!this.sent) {
            this.Push(Buffer.from(this.str));
            this.sent = true
        }
        else {
            this.Push(null)
        }
    }
}

const stringStream = new ReadableString('string to be streamed...')
1
Russell Briggs

Le code JavaScript est typé, donc si vous copiez simplement l'API d'un flux lisible , cela fonctionnera parfaitement. En fait, vous ne pouvez probablement pas implémenter la plupart de ces méthodes ou les laisser comme des talons; tout ce que vous devez implémenter est ce que la bibliothèque utilise. Vous pouvez également utiliser le préfabriqué EventEmitter class de Node pour traiter les événements, afin que vous n'ayez pas à implémenter addListener et vous-même.

Voici comment vous pouvez l'implémenter dans CoffeeScript:

class StringStream extends require('events').EventEmitter
  constructor: (@string) -> super()

  readable: true
  writable: false

  setEncoding: -> throw 'not implemented'
  pause: ->    # nothing to do
  resume: ->   # nothing to do
  destroy: ->  # nothing to do
  pipe: -> throw 'not implemented'

  send: ->
    @emit 'data', @string
    @emit 'end'

Ensuite, vous pourriez l'utiliser comme ceci:

stream = new StringStream someString
doSomethingWith stream
stream.send()
1
icktoofay