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
发射,因为readable
stream在读取时产生如此大的块。 我希望不再看到任何日志表示转移已完成。 但是你真的需要注册.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保持安全的方式。