109

如何在 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.");
   }
});

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

4

10 回答 10

97

编辑:好消息!从 Node.js 8.0.0 开始readable.destroy正式可用:https ://nodejs.org/api/stream.html#stream_readable_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 事件以准确了解文件何时关闭。除非数据完全消耗,否则不会触发end 事件。


请注意,destroy(和close)函数是特定于fs.ReadStream 的。没有通用流的一部分。可读的“接口”。

于 2015-04-22T18:28:38.177 回答
42

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

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

显然可以完成这项工作:) 它实际上做了类似于你的isEnded.

编辑 2015 年 4 月 19 日根据以下评论,并澄清和更新:

  • 这个建议是一个 hack,没有记录。
  • 尽管从当前lib/fs.js来看,它在 1.5 年后仍然有效。
  • 我同意下面关于打电话destroy()更可取的评论。
  • 如下正确所述,这适用于fs ReadStreams's,而不适用于泛型Readable

至于通用解决方案:至少从我对文档的理解和快速浏览_stream_readable.js.

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

于 2013-10-09T16:17:14.830 回答
25

今天,在节点 10 中

readableStream.destroy()

是关闭可读流的官方方式

https://nodejs.org/api/stream.html#stream_readable_destroy_error

于 2018-06-03T12:40:08.470 回答
14

你不能。从 Node 5.3.0开始,没有记录的方法可以关闭/关闭/中止/销毁通用可读流。这是 Node 流架构的限制。

正如此处的其他答案所解释的那样,Node 提供的 Readable 的特定实现存在未记录的黑客攻击,例如fs.ReadStream。但是,这些不是任何 Readable 的通用解决方案。

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

编辑:这是我的解决方法:通过一系列复杂的调用为我的管道实施。.destroy()unpipe()在所有这些复杂性之后,它并不是在所有情况下都能正常工作

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

于 2015-12-31T14:59:03.990 回答
11

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

来自nodejs 文档

如果传入的不是 null 值,push() 方法会在队列中添加一块数据,供后续流处理器使用。如果传递了 null ,则表示流结束 (EOF),在此之后不能再写入数据。

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

于 2016-04-21T06:19:00.987 回答
6

这个销毁模块旨在确保流被销毁,处理不同的 API 和 Node.js 错误。现在是最好的选择之一。

注意。从节点 10 开始,您可以使用该.destroy方法而无需进一步依赖。

于 2017-06-10T18:44:19.020 回答
3

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

来自官方文档

可读的简历():

返回:这个

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

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

var readable = getReadableStreamSomehow();
readable.resume();
readable.on('end', () => {
  console.log('got to the end, but did not read anything');
});
于 2016-04-04T13:33:42.693 回答
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

于 2016-06-07T14:39:11.577 回答
2

这里的代码可以很好地解决问题:

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

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

于 2017-05-02T05:12:56.963 回答
-1

要在某些调用后停止回调执行,您必须使用具有特定 processID 的 process.kill

const csv = require('csv-parser');
const fs = require('fs');

const filepath = "./demo.csv"
let readStream = fs.createReadStream(filepath, {
    autoClose: true,
});
let MAX_LINE = 0;


readStream.on('error', (e) => {
        console.log(e);
        console.log("error");
    })

    .pipe(csv())
    .on('data', (row) => {

        if (MAX_LINE == 2) {
            process.kill(process.pid, 'SIGTERM')
        }
        // console.log("not 2");
        MAX_LINE++
        console.log(row);
    })

    .on('end', () => {
        // handle end of CSV
        console.log("read done");
    }).on("close", function () {
        console.log("closed");
    })

于 2021-12-20T09:44:57.430 回答