如何确保Node.js函数仅在流结束后运行?

时间:2014-01-09 20:50:44

标签: node.js callback stream

我正在通过尝试重新创建一些我在C#中编写过的实用程序应用程序来匆忙学习Node.js。我对我正在写的一个程序中发生的事情感到困惑。我想要这个程序要做的是在文件系统上打开一个文件,gzip该文件,然后将gzip压缩数据发送到另一台服务器。为了测试,我决定“将gzip压缩数据保存到文件系统,然后再读回来验证你做对了。”

所以我希望我的程序能做的是:

  1. 创建输出文件。
  2. 打印“创建的测试输出文件”。
  3. 打印“尝试重新读取数据。”
  4. 阅读文件。
  5. 将纯文本输出到控制台。
  6. 反而会发生什么:

    1. 创建输出文件。
    2. “正在尝试重新读取数据。”印刷。
    3. “创建测试输出文件。”印刷。
    4. 我没有控制台输出。
    5. 这是我的代码(如果我的风格很糟糕,请不要向我扔石头!):

      var inputFilePath = "data.xml";
      var fs = require('fs');
      var zlib = require('zlib');
      
      var inputStream = fs.createReadStream(inputFilePath)
          .on('end', function() {
              console.log("Created test output file.");
          });
      
      var gzipStream = zlib.createGzip();
      inputStream.pipe(gzipStream);
      
      var outputFile = fs.createWriteStream('output.gzip');
      gzipStream.pipe(outputFile);
      
      console.log('Attempting to re-read the data.');
      var testInput = fs.createReadStream('output.gzip');
      var unzip = zlib.createGunzip();
      testInput.pipe(unzip).on('data', function(chunk) {
          console.log(chunk.toString('utf8'));
      });
      

      我怀疑流媒体内容是异步发生的,这就是为什么我看到控制台输出的顺序与我预期的不同。如果这是真的,这是一个问题,因为我在尝试打开之前需要输出文件准备就绪。我注意到writable.end()并且认为这将是解决方案,但我不明白当我在不同的地方调用它时会发生什么:

      • 如果我在尝试读取文件之前调用outputFile.end(),则输出文件为空。我想这是因为它在写入发生之前关闭了流。
      • 如果我改为呼叫gzipStream.end(),我不会收到“创建的测试输出文件”消息,但会创建一个消息!

      修改

      我想出了第二部分。在给定的代码中,我应该在data之前设置unzip事件的处理程序,然后再调用pipe()。现在设置代码的方式,我设置为在管道返回的流上处理事件,但从不从THAT流中读取,因此我的处理程序永远不会被调用。

1 个答案:

答案 0 :(得分:0)

我偶然发现了这个解决方案。从概念上看,表达我想要一个订单的方式就是说,“当输入流中没有更多数据时,开始处理它生成的输出文件。”大大简化:

var inputFilePath = "data.xml";
var fs = require('fs');
var zlib = require('zlib');

function testOutput() {
    console.log('Attempting to re-read the data.');
    var testInput = fs.createReadStream('output.gzip');
    var unzip = zlib.createGunzip();
    unzip.on('data', function(chunk) {
        console.log(chunk.toString('utf8'))
    });

    testInput.pipe(unzip);
};

// Load input file stream
var inputStream = fs.createReadStream(inputFilePath);

// Pipe the file stream into a gzip stream
var gzipStream = zlib.createGzip();
gzipStream.on('end', function() {
    console.log("Created test output file.");
    testOutput();
});

var outputFile = fs.createWriteStream('output.gzip');
inputStream.pipe(gzipStream).pipe(outputFile);

pipe()调用清空inputStream,然后gzipStream,调用testOutput()