Node.js的writable.write返回false?

我想上传(stream)控制写入过程。 但写入过程总是返回false。 大file upload过程停止。 代码的输出如下;

> Node app.js > False > False > False > False 

我究竟做错了什么?

我的代码

app.js

 var http = require('http'); var fs = require('fs'); http.createServer(function(req, res){ var readable = fs.createReadStream('read.mkv'); var writable = fs.createWriteStream('write.mkv'); readable.on('data', function(chunk){ var buffer = writable.write(chunk); if(!buffer){ // ----> Always false! Why???? readable.pause(); } console.log(buffer); }); writable.on('drain', function(){ readable.resume(); }); }).listen(8090); 

我已经修改了你的程序来显示更多关于正在发生的事情的信息:

 'use strict'; const fs = require('fs'); const readable = fs.createReadStream('read.mkv'); const writable = fs.createWriteStream('write.mkv'); readable.on('data', function(chunk){ var buffer = writable.write(chunk); if(!buffer){ // ----> Always false! Why???? readable.pause(); } console.log(buffer, chunk.length); }); writable.on('drain', function(){ readable.resume(); console.log('drain'); }); 

输出:

 $ node blah.js false 65536 drain false 65536 drain false 65536 drain true 8192 

我也使用了不同大小的文件作为input,所以我有一个true的输出结束。 如果我将read.mkv的大小增加了10000字节,最后一行会显示false 18192

发生的事情是read()返回的每个块都足够大,导致写入stream超过其默认为16384 highWaterMark (假定fs.createWriteStream返回的stream)。 从输出中的数字可以看出,除了最后一个,每个read() (err,每个'data'事件)产生65536个字节。 由于将这一数量的数据writable导致数据超过其highWaterMark ,因此build议在继续之前等待'drain'

所以,简单地说,你总是看到false发射,因为readablestream在读取时产生如此大的块。 我希望不再看到任何日志表示转移已完成。 但是你真的需要注册.on('end').on('error')来解决这个问题。

对于这样一个简单的例子,只需使用readable.pipe()就好:

 readable.pipe(writable); 

这会自动处理'drain'给你。 它甚至会为你调用writable.end()

请注意, pipe()如果遇到读取或写入错误,将不会调用writable.end() 。 如果你有一个长时间运行的stream程需要对stream错误进行恢复,那么你需要确保处理错误并closuresstream,以防止程序运行足够长的时间来达到文件描述符限制。

什么是false意思

stream允许程序通过一次处理大块数据来扩展到大量数据,而不是将其全部加载到内存中。 在最终写出数据之前,数据stream可以被组织成表示数据的各种转换的stream水线。 当write()返回false ,它表明它已经收到足够的数据来保持它忙一段时间。 如果你继续发送它的大块,它会继续接受这些块。 然而,其积压的数据将增长,并开始消耗更多的内存。 如果忽略这个返回值并且从一个非常大的源代码继续发送数据,那么甚至可能导致程序耗尽地址空间并崩溃或卡住。 为了保持代码的可扩展性,您应该尊重false回报,并像在代码中一样等待'drain ”。

然而, false并不意味着发生了任何不好的事情或者有任何错误。 事实上,在源码stream比目标码stream更快的情况下,预计会发生这种情况,并且是API API保持安全的方式。