基本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上运行脚本时,没有任何东西被发送到标准输出,并且不会引发任何错误。 我有几个问题:

  1. 如果你想把内存中的某个值放到stream中,那么最好的办法是什么?
  2. pushqueue之间有什么区别?
  3. 如果我在调用pipe()之前或之后调用end() ,是否有关系?
  4. 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中推出; 在实现自己的ReadableDuplexTransformstream时只使用push()

其次,在设置pipe() (或添加了一些事件侦听器) 之后 ,您只需要将数据write()到stream中。 如果你写了一个没有连接到另一端的stream,那么你写的数据将会丢失。 正如@naomik所指出的那样,这通常是不正确的,因为一个Writablestream将缓冲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(); 

现在,对于你的问题:

  1. 从内存中获取数据到可写入stream的最简单的方法是简单地write()它,就像我们在你的例子中用stream.wrtie('asdf')做的一样。
  2. 据我所知,这个stream没有queue()函数,你的意思是write() ? 就像我上面所说的, write()用于将数据放入stream中, push()用于将数据从stream中推出。 只在你的拥有stream实现中调用push()
  3. 只有所有数据已经​​写入stream之后调用end()end()基本上是这样说的:“好吧,我现在完成了,请完成你正在做的事情并closuresstream。”
  4. 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…如果你使用写(…)而不是推(…)会发生什么?