基本stream问题:难以向stdout发送string
我刚开始学习节点中的stream。 我在内存中有一个string,我想把它放在一个应用了转换的stream中,并通过process.stdout
。 这是我的尝试:
var through = require('through'); var stream = through(function write(data) { this.push(data.toUpperCase()); }); stream.push('asdf'); stream.pipe(process.stdout); stream.end();
这是行不通的。 当我通过节点在cli上运行脚本时,没有任何东西被发送到标准输出,并且不会引发任何错误。 我有几个问题:
- 如果你想把内存中的某个值放到stream中,那么最好的办法是什么?
-
push
和queue
之间有什么区别? - 如果我在调用
pipe()
之前或之后调用end()
,是否有关系? -
end()
等于push(null)
?
谢谢!
只需使用香草streamAPI
var Transform = require("stream").Transform; // create a new Transform stream var stream = new Transform({ decodeStrings: false, encoding: "ascii" }); // implement the _transform method stream._transform = function _transform(str, enc, done) { this.push(str.toUpperCase() + "\n"; done(); }; // connect to stdout stream.pipe(process.stdout); // write some stuff to the stream stream.write("hello!"); stream.write("world!"); // output // HELLO! // WORLD!
或者你可以build立你自己的stream构造函数。 这实际上是streamAPI的使用方式
var Transform = require("stream").Transform; function MyStream() { // call Transform constructor with `this` context // {decodeStrings: false} keeps data as `string` type instead of `Buffer` // {encoding: "ascii"} sets the encoding for our strings Transform.call(this, {decodeStrings: false, encoding: "ascii"}); // our function to do "work" function _transform(str, encoding, done) { this.push(str.toUpperCase() + "\n"); done(); } // export our function this._transform = _transform; } // extend the Transform.prototype to your constructor MyStream.prototype = Object.create(Transform.prototype, { constructor: { value: MyStream } });
现在像这样使用它
// instantiate var a = new MyStream(); // pipe to a destination a.pipe(process.stdout); // write data a.write("hello!"); a.write("world!");
产量
HELLO! WORLD!
一些关于.push
vs .write
其他说明。
-
.write(str)
将数据添加到可写缓冲区。 这意味着被称为外部。 如果你想像一个双工文件句柄的stream,它就像fwrite
,只有缓冲。 -
.push(str)
将数据添加到可读的缓冲区。 它只是打算从我们的stream中被调用。 -
.push(str)
可以多次调用。 看看如果我们改变我们的function会发生什么function _transform(str, encoding, done) { this.push(str.toUpperCase()); this.push(str.toUpperCase()); this.push(str.toUpperCase() + "\n"); done(); }
产量
HELLO!HELLO!HELLO! WORLD!WORLD!WORLD!
首先,你要使用write()
,而不是push()
。 write()
将数据放入stream中, push()
将数据从stream中推出; 在实现自己的Readable
, Duplex
或Transform
stream时只使用push()
。
其次,在设置 pipe()
(或添加了一些事件侦听器) 之后 ,您只需要将数据write()
到stream中。如果你写了一个没有连接到另一端的stream,那么你写的数据将会丢失。 正如@naomik所指出的那样,这通常是不正确的,因为一个Writable
stream将缓冲write()
。 在你的例子中,你需要在pipe()
之后write()
。 否则,在向STDOUT
写入任何内容之前,该过程将结束。 这可能是由于through
模块是如何实现的,但我不知道这一点。
所以,考虑到这一点,您可以对您的示例进行一些简单的更改以使其正常工作:
var through = require('through'); var stream = through(function write(data) { this.push(data.toUpperCase()); }); stream.pipe(process.stdout); stream.write('asdf'); stream.end();
现在,对于你的问题:
- 从内存中获取数据到可写入stream的最简单的方法是简单地
write()
它,就像我们在你的例子中用stream.wrtie('asdf')
做的一样。 - 据我所知,这个stream没有
queue()
函数,你的意思是write()
? 就像我上面所说的,write()
用于将数据放入stream中,push()
用于将数据从stream中推出。 只在你的拥有stream实现中调用push()
。 - 只有在所有数据已经写入stream之后调用
end()
。end()
基本上是这样说的:“好吧,我现在完成了,请完成你正在做的事情并closuresstream。” -
push(null)
与end()
几乎等价。 这就是说,除非你在自己的stream实现中(如上所述),否则不要调用push(null)
)。 调用end()
几乎总是比较合适的。
基于stream的示例( http://nodejs.org/api/stream.html#stream_readable_pipe_destination_options )
并通过( https://www.npmjs.org/package/through )
它看起来不像你正在使用你的stream…如果你使用写(…)而不是推(…)会发生什么?