基本流问题:难以将字符串发送到stdout

时间:2014-08-26 14:50:57

标签: node.js

我刚开始学习节点中的流。我在内存中有一个字符串,我想把它放在一个应用转换的流中,并将其传递给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 via节点上运行脚本时,没有任何内容发送到stdout并且不会抛出任何错误。我有几个问题:

  1. 如果你想在内存中加入一个值,那么最好的方法是什么?
  2. pushqueue之间的区别是什么?
  3. 在致电end()之前或之后致电pipe()是否重要?
  4. end()是否等同于push(null)
  5. 谢谢!

3 个答案:

答案 0 :(得分:2)

只需使用vanilla stream API

即可
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!

或者您可以构建自己的流构造函数。这实际上就是要使用流API的方式

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.write的其他一些说明。

  • .write(str)将数据添加到可写缓冲区。它应该被称为外部。如果您将流视为双工文件句柄,它就像fwrite一样,只是缓冲。

  • .push(str)将数据添加到可读缓冲区。它只能从我们的流中调用。

  • .push(str)可以多次调用。观察如果我们将功能更改为

    会发生什么
    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!
    

答案 1 :(得分:2)

首先,您要使用write(),而不是push()write()将数据放入流中,push()将数据推出流;您在实施自己的push()ReadableDuplex流时仅使用Transform

其次,您只需要{<1}}数据到设置write()(或添加一些事件侦听器)。如果您写入一个没有连接到另一端的数据流,那么您编写的数据将会丢失。正如@naomik指出的那样,这通常不正确,因为pipe()流将会缓冲区Writable。在您的示例中,您需要在write()之后write()。否则,该过程将在向pipe()写入任何内容之前结束。这可能是由于STDOUT模块的实现方式,但我肯定不知道。

因此,考虑到这一点,您可以对示例进行一些简单的更改以使其工作:

through

现在,提出您的问题:

  1. 从内存中获取数据到可写流的最简单方法就是var through = require('through'); var stream = through(function write(data) { this.push(data.toUpperCase()); }); stream.pipe(process.stdout); stream.write('asdf'); stream.end(); ,就像我们在您的示例中使用write()一样。
  2. 据我所知,该流没有stream.wrtie('asdf')功能,您的意思是queue()吗?就像我上面说的那样,write()用于将数据放入流中,write()用于将数据推出流。只在您自己的流实施中调用push()
  3. 只有在所有数据都写入您的信息流后才能致电push() end()基本上说:“好的,我现在已经完成了。请完成你正在做的事情并关闭游戏。”
  4. end()几乎相当于push(null)。话虽这么说,除非你在你自己的流实现中做(如上所述),否则不要调用end()。调用push(null)几乎总是更合适。

答案 2 :(得分:0)

基于流(http://nodejs.org/api/stream.html#stream_readable_pipe_destination_options

的示例

并通过(https://www.npmjs.org/package/through

看起来你没有正确使用你的流......如果你使用write(...)而不是push(...)会怎么样?