javascript work Como criar streams de string em Node.Js?




work with stream nodejs (8)

Eu estou usando uma biblioteca, ya-csv , que espera um arquivo ou um fluxo como entrada, mas eu tenho uma seqüência de caracteres.

Como converto essa string em um fluxo no Node?


Não use a resposta do residente de Jo Liss. Ele funcionará na maioria dos casos, mas no meu caso ele me perdeu umas boas 4 ou 5 horas. Não há necessidade de módulos de terceiros para fazer isso.

RESPOSTA NOVA :

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

Este deve ser um fluxo legível totalmente compatível. Veja aqui para mais informações sobre como usar fluxos corretamente.

RESPOSTA ANTIGA : Apenas use o fluxo PassThrough nativo:

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

Observe que o evento 'close' não é emitido (o que não é exigido pelas interfaces de fluxo).


Edit: A resposta de Garth é provavelmente melhor.

Meu antigo texto de resposta é preservado abaixo.

Para converter uma string em um fluxo, você pode usar um fluxo interrompido:

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

Exemplo:

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

em café-script:

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

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

use-o:

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

Outra solução é passar a função read para o construtor de Readable (cf. opções legíveis por fluxo de doc)

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

você pode depois de usar s.pipe por exemplo


Como @substack me corrigiu em #node , a nova API de fluxos no Node v10 torna isso mais fácil:

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

… Após o qual você pode pipe lo livremente ou passá-lo para o consumidor pretendido.

Não é tão limpo quanto o one-liner do resumer , mas evita a dependência extra.

( Atualização: na v0.10.26 até v9.2.1 até o momento, uma chamada para push diretamente do prompt REPL irá travar com uma exceção not implemented se você não tiver definido _read . Não irá travar dentro de uma função ou script. Se a inconsistência o deixar nervoso, inclua o noop .)


Eu me cansei de ter que reaprender isso a cada seis meses, então eu acabei de publicar um módulo npm para abstrair os detalhes da implementação:

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

Este é o núcleo do módulo:

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 é a string que deve ser passada para o construtor após a invocação e será transmitida pelo fluxo como dados. options são as opções típicas que podem ser passadas para um fluxo, de acordo com a documentação .

De acordo com Travis CI, ele deve ser compatível com a maioria das versões do nó.


O JavaScript é tipificado por pato, então, se você simplesmente copiar a API de um fluxo legível , ele funcionará muito bem. Na verdade, você provavelmente não pode implementar a maioria desses métodos ou apenas deixá-los como stubs; tudo o que você precisará implementar é o que a biblioteca usa. Você também pode usar a classe EventEmitter pré-construída do EventEmitter para lidar com eventos, assim você não precisa implementar o addListener e você mesmo.

Veja como você pode implementá-lo no 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'

Então você poderia usá-lo assim:

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

Basta criar uma nova instância do módulo de stream e personalizá-lo de acordo com suas necessidades:

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




inputstream