管道读取流写入流时听写吗?

时间:2017-07-28 19:04:44

标签: node.js

我有代码:

const readStream = fs.createReadStream(readFilename, {
    highWaterMark: 10 * 1024
});

const writeStream = fs.createWriteStream(writeFilename, {
    highWaterMark: 1 * 1024
});

readStream.pipe(writeStream);

如您所见,两者的缓冲区(highWaterMark)大小不同。读取具有更高的缓冲区,当读取管道写入它确实对写入缓冲区来说太多了。它在内存中保留9 * 1014,在处理完整个负载后,它会调用drain。这很好。

然而。当写入通过writable.write手动写入时,会返回false,因此您可以更改读取流以使缓冲区更低(如果这是您想要的)。

我的问题是,因为我直接滚动,无论如何都要听写在可写上的写事件?我唯一可以听到的是之后的排水事件已经过多了。

2 个答案:

答案 0 :(得分:1)

一般的回答是“不,因为没有必要”。,但军事程度较低的人会说“ ”,但又会产生另一种后果。

首先,对于drain事件在管道流中的含义有误解:

  • 您假设Writable缓冲区耗尽时会调用它,但这仅是node.js内部缓冲区,而不是通往文件系统的实际管道。
  • 另外,您并不是唯一一个正在阅读该书的人-pipe方法实际上在两个流周围都创建了许多侦听器和pause / resume逻辑。
  • 所以实际上发生的是Readable正在监听Writable#drain事件,以将更多数据推入缓冲区。

第二,如前所述-Writable并没有实现对已写入特定chunk的任何确认,这仅仅是因为在stringBuffer块上,很难说出它们实际上是什么时候写的(在gzip流的简单情况下,有时甚至不可能将一部分块写到实际磁盘上也是如此)。

有一种方法可以使距离足够近(每个块获得几乎精确的确认):

const {PassThrough} = require("stream");

fs.createReadStream(readFilename, {
    highWaterMark: 10 * 1024
})
/* we pipe the readable to a buffer in a passthrough stream */
.pipe(new PassThrough({
    highWaterMark: 1024
}))
/* pipe returns the stream we piped to */
/* now we pipe again, but to a stream with no highWaterMark */
.pipe(
    new PassThrough({
        highWaterMark: 1
    })
    .on("data", () => { 
        /* here's your confirmation called just before this chunk is written and after the last one has started to be written */ 
    })
)
/* and there we push to the write stream */
.pipe(
    fs.createWriteStream(writeFilename, {
        highWaterMark: 1
    })
);

当然,这肯定会对性能产生影响,但我不知道它有多大,但是它将使读取方或多或少有效且可写将获得所需的缓冲区-但要有一些额外的CPU和一些微型每个块的延迟。

要由您来测试。

See more on streams, especially PassThrough here.

答案 1 :(得分:-2)

是的。您可以收听data事件:

readStream.on('data', data => console.log(data))