Как создать потоки из строки в Node.Js?

Я использую библиотеку ya-csv, которая ожидает ввода файла или потока, но у меня есть строка.

Как преобразовать эту строку в поток в Node?

Ответ 1

Как @substack исправил меня в #node, новый API потоков в Node v10 делает это проще:

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

... после чего вы можете свободно трубы он или иным образом передать его предполагаемого потребителя.

Это не так чисто, как возобновить однострочник, но это позволяет избежать дополнительной зависимости.

(Update: в v0.10.26 через v9.2.1 до сих пор, призыв push непосредственно из REPL строки будет врезаться с not implemented исключением, если вы не ставили _read. Он не будет врезаться внутри функции или скрипта. Если непоследовательность заставляет вас нервничать, noop.)

Ответ 2

Не используйте ответ джо Лисса. В большинстве случаев это будет работать, но в моем случае я потерял 4 или 5 часов поиска ошибок. Для этого не нужны сторонние модули.

НОВЫЙ ОТВЕТ:

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

Это должен быть полностью совместимый поток для чтения. Смотрите здесь для получения дополнительной информации о том, как правильно использовать потоки.

СТАРЫЙ ОТВЕТ: Просто используйте собственный поток 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
})

Обратите внимание, что событие 'close' не генерируется (что не требуется для потоковых интерфейсов).

Ответ 3

Просто создайте новый экземпляр модуля stream и настройте его в соответствии с вашими потребностями:

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

или

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

Ответ 4

Изменить: ответ Garth, вероятно, лучше.

Мой старый текст ответа сохраняется ниже.


Чтобы преобразовать строку в поток, вы можете использовать приостановленный through поток:

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

Пример:

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

Ответ 6

в кофе script:

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

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

используйте его:

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

Ответ 7

Другое решение - передать функцию чтения в конструктор Readable (см. Параметры чтения потока cf doc)

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

Вы можете после использования s.pipe для примера

Ответ 8

Я устал от переучивания этого каждые шесть месяцев, поэтому я просто опубликовал модуль npm, чтобы абстрагироваться от деталей реализации:

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

Это ядро модуля:

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 - это string, который должен быть передан конструктору при вызове и будет выведен потоком в виде данных. options - это типичные параметры, которые могут быть переданы в поток согласно документации.

Согласно Travis CI, он должен быть совместим с большинством версий узла.

Ответ 9

JavaScript утилит, поэтому, если вы просто скопируете читаемый поток API, все будет хорошо. Фактически, вы, вероятно, не сможете реализовать большинство этих методов или просто оставить их в качестве заглушек; все, что вам нужно реализовать, - это то, что использует библиотека. Вы можете использовать Node предварительно построенный EventEmitter класс для обработки событий, так что вам не нужно реализовывать addListener и таким образом.

Здесь вы можете реализовать его в 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'

Тогда вы можете использовать его так:

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

Ответ 10

Вот простое решение в 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...')