如何关闭可读流(结束之前)?


89

如何在Node.js中关闭可读流

var input = fs.createReadStream('lines.txt');

input.on('data', function(data) {
   // after closing the stream, this will not
   // be called again

   if (gotFirstLine) {
      // close this stream and continue the
      // instructions from this if
      console.log("Closed.");
   }
});

这比以下更好:

input.on('data', function(data) {
   if (isEnded) { return; }

   if (gotFirstLine) {
      isEnded = true;
      console.log("Closed.");
   }
});

但这不会停止阅读过程...


6
警告:此问题仅在fs模块的上下文中。close在中不存在Stream.Readable
zamnuts 2014年

3
好消息。节点版本8提供stream.destroy()
joeytwiddle

你不能打电话吗?readable.push(null) && readable.destroy();
亚历山大·米尔斯

Answers:


39

调用 input.close()。它不在文档中,但是

https://github.com/joyent/node/blob/cfcb1de130867197cbc9c6012b7e84e08e53d032/lib/fs.js#L1597-L1620

显然可以完成工作:)它实际上执行与您相似的操作 isEnded

EDIT 2015-Apr-19根据以下评论,并进行澄清和更新:

  • 该建议是黑客行为,未记录在案。
  • 虽然看当前 lib/fs.js来看,它仍然可以在> 1.5年后使用。
  • 我同意以下有关致电的评论 destroy()更好。
  • 如下面正确说明的,这适用于fs ReadStreams,不适用于通用Readable

至于通用解决方案:至少从我对文档的理解和快速浏览来看,它似乎并不存在_stream_readable.js

我的建议是将您的可读流置于暂停模式,至少防止上游数据源中的进一步处理。如文档所述,不要忘记unpipe()并删除所有data事件侦听器,以便pause()实际上暂停


使其更长:从文档中添加一些参考!:-)
尼卡比曹

2
很好!源代码似乎是最好的文档资源。;-)
尼卡比曹

实际上,我宁愿打电话给他destroy。如果将autoClose设置为true,那么至少就是这样。通过查看源代码(今天),差异很小(destroy调用close),但是将来可能会改变
Marcelo Diniz 2014年

@NitzanShaked文件已更新。这是正确的链接:github.com/joyent/node/blob/…吗?(它包含提交ID,所以它不会在将来被改变)
尼卡比曹

4
没有close()对象可读的,有没有解决方法?我的数据交换总是不完整...
CodeManX 2014年

71

编辑:好消息!从Node.js 8.0.0开始readable.destroy正式可用:https : //nodejs.org/api/stream.html#stream_visible_destroy_error

ReadStream.destroy

您可以随时调用ReadStream.destroy函数。

var fs = require('fs');

var readStream = fs.createReadStream('lines.txt');
readStream
    .on('data', function (chunk) {
        console.log(chunk);
        readStream.destroy();
    })
    .on('end', function () {
        // This may not been called since we are destroying the stream
        // the first time 'data' event is received
        console.log('All the data in the file has been read');
    })
    .on('close', function (err) {
        console.log('Stream has been destroyed and file has been closed');
    });

ReadStream.destroy没有公开功能(Node.js v0.12.2),但是您可以查看GitHub上源代码2012年10月5日,确认))。

destroy函数在内部将ReadStream实例标记为已销毁,然后调用该close函数以释放文件。

您可以侦听close事件以确切了解文件何时关闭。在结束事件将不会触发除非数据被完全消耗。


注意destroy(和close)函数特定于fs.ReadStream。没有通用stream.read “接口”的一部分。


至少在最新版本的Node中(没有检查其他版本),文件描述符会自动关闭。就是说,我还没有做过任何彻底的测试来确保error如果从不读取流,则最终将其触发。除此之外,我唯一担心的其他泄漏是事件处理程序,再一次,我对此不确定性为100%,但是在2010年以撒的福音中确实说处理程序是在对发射器进行
gc操作

1
如果数据太小,on('data') 只会触发一次,所以不会触发任何数据.close(),只是提醒其他人。
bitfishxyz


12

你不能 从节点5.3.0开始,没有记录的关闭/关闭/中止/销毁通用Readable流的方法。这是Node流体系结构的限制。

正如这里的其他答案所解释的那样,Node提供了针对Readable的特定实现的未公开记录的hack,例如fs.ReadStream。。这些不是任何Readable的通用解决方案。

如果有人可以在这里证明我错了,请这样做。我希望能够做到我说的是不可能的,并且很高兴得到纠正。

编辑:这是我的解决方法:通过一系列复杂的调用为我的管道实现。.destroy()unpipe()而且毕竟复杂了,它在所有情况下都无法正常工作

编辑:节点v8.0.0 destroy()为可读流添加了一个api


1
现在stream.pipeline,它声称可以处理“转发错误并正确清理并在管道完成时提供回调”。有帮助吗?
andrewdotn

11

在版本中,4.*.*将空值推送到流中将触发EOF信号。

来自Node.js文档

如果传递了非null值,则push()方法会将数据块添加到队列中,以供后续流处理器使用。如果传递了null,则表示流结束(EOF),之后将无法再写入数据。

在尝试了此页面上的许多其他选项之后,这对我有用。


1
为我工作。但是,我需要避免在将null推入以获得预期的行为后即调用该函数(即整个流暂停)之后避免调用done()回调。
Rich Apodaca


3

您可以使用清除和关闭流yourstream.resume(),这将转储流中的所有内容并最终将其关闭。

官方文档

read.resume():

返回:这个

此方法将使可读流恢复发射“数据”事件。

此方法会将流切换到流模式。如果您不想使用流中的数据,但是希望到达其“结束”事件,则可以调用stream.resume()来打开数据流。

var readable = getReadableStreamSomehow();
readable.resume();
readable.on('end', () => {
  console.log('got to the end, but did not read anything');
});

这可以称为“排出”流。在我们的例子中,我们当然有一个'data'事件侦听器,但是我们使它检查一个布尔值,if (!ignoring) { ... }因此在耗尽流时它不会处理数据。ignoring = true; readable.resume();
joeytwiddle

5
当然,这假设流将'end'在某个时候出现。并非所有流都可以做到这一点!(例如,永远每秒发送日期的流。)
joeytwiddle

3

这是一个老问题,但我也在寻找答案,并找到了最适合我的实现方案。无论endclose事件被发出,所以我觉得这是最干净的解决方案。

这将在节点4.4。*(撰写本文时为稳定版本)中达到目的:

var input = fs.createReadStream('lines.txt');

input.on('data', function(data) {
   if (gotFirstLine) {
      this.end(); // Simple isn't it?
      console.log("Closed.");
   }
});

有关详细说明,请参见:http : //www.bennadel.com/blog/2692-you-have-to-explicitly-end-streams-after-pipes-break-in-node-js.htm


2

这段代码可以很好地完成技巧:

function closeReadStream(stream) {
    if (!stream) return;
    if (stream.close) stream.close();
    else if (stream.destroy) stream.destroy();
}

writeStream.end()是关闭writeStream的首选方法。


为什么提到.end()是首选方法,但是您的代码使用close和destroy甚至不使用end?
卢卡斯B

1
我在示例中关闭了readStream ... writeStream-使用.end
g00dnatur3
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.