如何在Node.Js中从字符串创建流?

pat*_*rit 155 javascript string inputstream stream node.js

我正在使用一个库,ya-csv,它要求文件或流作为输入,但我有一个字符串.

如何将该字符串转换为Node中的流?

Gar*_*idd 174

作为@substack在纠正我#node,新的流API在节点V10使这更容易:

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

...之后,您可以自由地管道或以其他方式将其传递给您的目标消费者.

它不像resumer one-liner 一样干净,但确实避免了额外的依赖.

(更新:在v0.10.26到v9.2.1到目前为止,如果你没有设置,push直接从REPL提示符调用会因not implemented异常_read而崩溃.它不会在函数或脚本中崩溃.如果不一致使你紧张,包括noop.)

  • 为什么要将`null`推入流的缓冲区? (8认同)
  • 从[文档(联系)](http://nodejs.org/api/stream.html#stream_readable_read_size_1):"所有可读流实现必须提供一个`_read`方法从底层资源获取数据." (6认同)
  • @dopatraman`null`告诉流它已经读完所有数据并关闭流 (5认同)
  • @eye_mew你需要先要求('stream') (2认同)
  • 看起来你不应该这样做.引用[文档](https://nodejs.org/download/nightly/v10.0.0-nightly20180405b29c36b807/docs/api/stream.html#stream_readable_push_chunk_encoding):"`read.push()`方法仅用于调用可读实现者,只能从`readable._read()`方法中获取. (2认同)
  • 根据 nodejs 文档,该示例违反了正确用法。即那些 s.push() 调用应该在 _read 实现中。请参阅文档 https://nodejs.org/api/stream.html#stream_readable_push_chunk_encoding 中的倒数第二条评论 (2认同)

B T*_*B T 110

不要使用Jo Liss的resumer答案.它可以在大多数情况下工作,但在我的情况下,它失去了我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
Run Code Online (Sandbox Code Playgroud)

这应该是完全兼容的可读流.有关如何正确使用流的更多信息,请参见此处.

旧答案:只需使用本机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
})
Run Code Online (Sandbox Code Playgroud)

请注意,不会发出'close'事件(流接口不需要).

  • 这个答案需要更多的赞成. (4认同)
  • @Finn如果没有任何args,你不需要javascript中的parens (2认同)
  • 2018 年不要使用“var”!但常量 (2认同)

小智 75

从节点 10.17 开始,stream.Readable 有一种from方法可以轻松地从任何可迭代对象(包括数组文字)创建流:

const { Readable } = require("stream")

const readable = Readable.from(["input string"])

readable.on("data", (chunk) => {
  console.log(chunk) // will be called once with `"input string"`
})
Run Code Online (Sandbox Code Playgroud)

请注意,至少在 10.17 和 12.3 之间,字符串本身是可迭代的,因此Readable.from("input string")可以工作,但每个字符发出一个事件。Readable.from(["input string"])将为数组中的每一项(在本例中为一项)发出一个事件。

另请注意,在以后的节点中(可能是 12.3,因为文档说当时函数已更改),不再需要将字符串包装在数组中。

https://nodejs.org/api/stream.html#stream_stream_readable_from_iterable_options

  • 根据 [stream.Readable.from](https://nodejs.org/api/stream.html#stream_stream_readable_from_iterable_options),*调用 Readable.from(string) 或 Readable.from(buffer) 不会使字符串或缓冲区出于性能原因,迭代以匹配其他流语义。* (2认同)

zem*_*rco 29

只需创建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
Run Code Online (Sandbox Code Playgroud)

要么

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');
Run Code Online (Sandbox Code Playgroud)

  • 此代码打破了流约定.`pipe()`应该至少返回目标流. (13认同)
  • 如果使用此代码,则不会调用结束事件.这不是创建可以普遍使用的流的好方法. (2认同)

Jo *_*iss 12

编辑: 加思的答案可能更好.

我的旧答案文本保留在下面.


要将字符串转换为流,您可以使用暂停的直通流:

through().pause().queue('your string').end()
Run Code Online (Sandbox Code Playgroud)

例:

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()
Run Code Online (Sandbox Code Playgroud)

  • Resumer很棒,但是如果您希望可以将流传递给未知的消费者,那么"在nextTick上自动恢复流"会产生惊喜!如果元数据的数据库保存成功,我有一些代码将内容流传送到文件.这是一个潜伏的错误,当db写入立即返回成功时,它恰好成功了!我后来重构了一些异步块内的东西,而且繁荣,流从来都不可读.经验教训:如果您不知道谁将使用您的流,请坚持使用through().pause().queue('string').end()技术. (2认同)
  • 我花了大约 5 个小时调试我的代码,因为我使用了这个答案的简历部分。如果你愿意的话那就太好了..删除它 (2认同)

Lor*_*ori 10

有一个模块:https://gist.github.com/kawanet/8aea35dc4a578f09757d

var str = require('string-to-stream')
str('hi there').pipe(process.stdout) // => 'hi there' 
Run Code Online (Sandbox Code Playgroud)


xin*_*ink 6

在咖啡脚本:

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

  _read: (size) ->
    @push @str
    @push null
Run Code Online (Sandbox Code Playgroud)

用它:

new StringStream('text here').pipe(stream1).pipe(stream2)
Run Code Online (Sandbox Code Playgroud)


Phi*_* T. 6

另一个解决方案是将read函数传递给Readable的构造函数(参见doc 流readeable选项

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

您可以使用s.pipe为例


Chr*_*ane 5

我厌倦了必须每六个月重新学习一次,所以我刚刚发布了一个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;
Run Code Online (Sandbox Code Playgroud)

strstring在调用时必须传递给构造函数的,并将由流作为数据输出。根据文档options,是可以传递到流的典型选项。

根据Travis CI,它应该与大多数版本的节点兼容。

  • 当我最初发布此代码时,我没有包括相关代码,但有人告诉我我对此不满意。 (2认同)

Rus*_*ggs 5

这是 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...')
Run Code Online (Sandbox Code Playgroud)