1

客观的

使用csv-write-stream和 fs 流将一个非常大的数组写入文件。

背景

我有一个小型应用程序,可将大量数据(数千个条目)写入 CSV 文件。为了实现这一点,我使用了前面提到的库,它只不过是 fs 流的掩码(方便)。但是,应用程序在运行时崩溃,我不知道为什么。

错误

文件被创建并且流开始写入它,但是在执行过程中我总是遇到同样的错误:

events.js:141
      throw er; // Unhandled 'error' event
      ^

Error: write after end
    at writeAfterEnd (_stream_writable.js:166:12)
    at WriteStream.Writable.write (_stream_writable.js:211:5)
    at ondata (_stream_readable.js:536:20)
    at emitOne (events.js:77:13)
    at emit (events.js:169:7)
    at Readable.read (_stream_readable.js:368:10)
    at flow (_stream_readable.js:751:26)
    at WriteStream.<anonymous> (_stream_readable.js:609:7)
    at emitNone (events.js:67:13)
    at WriteStream.emit (events.js:166:7)

代码

我知道这个错误与这段代码有关:

let writer = csvWriter({
    headers: ['country', 'postalCode']
});
let fsStream = fs.createWriteStream('output.csv');
writer.pipe(fsStream);

//very big array !
currCountryCodes = [{country: 'A', postalCode: 0}, {country: 'B', postalCode: 1 }];

for (let j = 0; j < currCountryCodes.length; j++) {
    writer.write(currCountryCodes[j]);
}

writer.end(function() {
  fsStream.end(function() {
    console.log('=== CSV written successfully, stopping application ===');
    process.exit();
  });
});

最具体的执行:

fsStream.end(function() {
        console.log('=== CSV written successfully, stopping application ===');
        process.exit();
      });

但我不明白为什么会这样。不知何故,它只发生在我正在编写的数组有数千行时,如果我只有十几行,它运行得很好。

问题

通过阅读错误,我得到的印象是在关闭流后我仍在写入文件,但这不可能发生,因为这些函数仅在所有内容都刷新到文件时运行(对吗?)

  • 我的代码有什么问题?
4

1 回答 1

1

问题是您(可以理解)假设当调用回调时writer.end(),不会再写入任何数据fsStream,但事实并非如此(如错误所示)。

writer是一个双工流,这意味着它既可读又可写。通过调用该.end()方法,您是在告诉它您将不再向其写入数据。但是,这并不意味着它仍然不可读。

当您随后 end 时fsStream,某些缓冲区中仍然可能有未刷新的数据将通过管道传输到fsStream,从而产生错误。

end您可以通过侦听on 事件来解决此问题writer,这是可读的等价于表示没有数据可供读取的信号:

writer.end(function() {
  writer.on('end', function() {
    fsStream.end(function() {
      console.log('=== CSV written successfully, stopping application ===');
      process.exit();
    });
  });
});

编辑:我认为当writer.end()被调用时,fsStream也会自动结束(所以fsStream.end()是多余的,并且它的回调可能不会被调用,因为finish事件已经被发出)。

如果您想确保所有数据都已刷新到输出文件,您可以监听finish事件:fsStream

writer.end(function() {
  fsStream.on('finish', function() {
    console.log('=== CSV written successfully, stopping application ===');
    process.exit();
  });
});

甚至:

fsStream.on('finish', function() {
  console.log('=== CSV written successfully, stopping application ===');
  process.exit();
});

writer.end();
于 2016-08-09T14:55:28.207 回答