将管道传输到stdout后如何重置stdin?

时间:2015-11-28 02:33:38

标签: javascript node.js io stream node.js-stream

你好,首先是SO问题!无论如何,我正在写一个小实验,以帮助更好地掌握流和更复杂的组合,结合流和&的承诺。

但是,我遇到了一个我目前无法解决的问题。如果您运行我的以下脚本然后输入input然后按ctrl-d结束输入:Node将尝试根据需要从stdin读取,但随后因stdin结束而立即关闭。 那么有更好的方法来写这个吗?或者有没有办法重置stdin流再次输入?或者有没有更好的方法来停止要求输入等待结束事件来解决我的承诺?

  

同样值得注意:在节点5.1.0上运行,使用ES2015(通过Babel 6)

import { Transform, Writable } from 'stream';
import util from 'util';

/**
 * Generic Transform
 * A test class to expiriment with creating a series of transforms
 *
 * @class
 * @extends {stream.Transform}
 */
class GenericTransform extends Transform {
  constructor (transformCallback, options={}) {
    super(Object.assign({}, options, { objectMode: true }));
    this._transformCallback = transformCallback;
  }

  /**
   * Transform
   * Stream method to transform read data, transform it, then move it to
   * the next stream.
   *
   * @method
   * @param {buffer} chunk - Buffer read from the input stream
   * @param {string} enc - Encoding of the input stream chunk buffer
   * @param {function} done - Callback to fire when transform is complete
   */
  _transform (chunk, enc, done) {
    try {
      this.push(this._transformCallback(chunk, this));
      done();
    }
    catch (e) {
      this.emit('error', e);
      done(e);
    }
  }
}

/**
 * Stdout Writer
 * Handles writing to stdout including linebreaks. I believe this is
 * required as writing to the stdout stream will not emit end\finish events.
 *
 * @class
 * @extends {stream.Writable}
 */
class StdoutWriter extends Writable {
  constructor (options) {
    super(options);
  }

  /**
   * Write
   * Stream method to write to process.stdout
   *
   * @method
   * @param {buffer} chunk - Text that gets written to the console
   * @param {string} enc - Encoding of the buffer
   * @param {callback} done - Callback to call when finished
   */
  _write (chunk, enc, done) {
    process.stdout.write(String(chunk) + '\n');
    done();
  }
}

/**
 * To
 * A shorthand function to create a generic transform method
 *
 * @method
 * @public
 * @param {function} transformer - transformer(data) returns new data
 * @returns {GenericTransform} A generic transform stream
 */
function to (transformer) {
  return new GenericTransform(transformer);
}

/**
 * Prompt
 * Requests input from the user then transforms it. Ideally it would ask for
 * input. When it receives a line it would stop reading, transform the data
 * then when the stream is finished ask the user for more input.
 *
 * @returns {Promise} A promise when the input has been read, transformed,
 *                    and displayed to the console via process.stdout.write
 */
function prompt () {
  process.stdout.write('Enter some input: ');
  return new Promise((resolve, reject) => {
    /** Start with process.stdin input stream */
    process.stdin

      /**
       * Converts the raw string input into a simple object with
       * a contents property and a date property
       *
       * @example
       * > Test
       * > (ctrl-d)
       *  {contents: "Test", date: 43993991013 }
       */
      .pipe(to((chunk) => {
        return {
          contents: String(chunk).trim(),
          date: Date.now()
        };
      }))

      /**
       * Takes the object created from the previous step and formats it as
       * a string using the inspect util. I suppose JSON.stringify would
       * also have worked.
       */
      .pipe(to((obj) => {
        return util.inspect(obj);
      }))

      /**
       * Pipe to a writable stream that writes to stdout. This is necessary
       * because the docs say that stdout never emit finish or end events.
       */
      .pipe(new StdoutWriter())

      /**
       * Handle errors and finish events by either resolving or rejecting
       * the parent promise object.
       */
      .on('finish', resolve)
      .on('error', reject);
  });
}

/** Set the encoding so it all comes in as strings */
process.stdin.setEncoding('utf8');

/**
 * This is the main driver logic for connecting the above pieces. It will
 * input the first question then keeps asking for more input. To stop
 * entering data press ctrl-d to send an EOF to process.stdin. This
 * at least causes the finish event to fire at the end but on the next
 * usage of prompt, everything is done.
 */
prompt()
  .then(prompt);

0 个答案:

没有答案
相关问题