(終了前に)読み取り可能なストリームを閉じる方法は?


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();
Alexander Mills

回答:


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()実際に一時停止するようにしてください


もっと長くしてください:ドキュメントからいくつかの参照を追加してください!:-)
IonicăBizău

2
とても良い!ソースコードは最高のドキュメントリソースのようです。;-)
IonicăBizău

destroy代わりに電話するほうがいいです。少なくとも、autoCloseをtrueに設定した場合に呼び出されます。ソースコードを見れば(今日)違いは最小限(destroy呼び出しclose)ですが、将来的には変更される可能性があります
Marcelo Diniz

@NitzanShakedファイルが更新されました。これは正しいリンクですか?github.com/joyent/node/blob/…?(それが将来的に変更することが習慣に、それは、IDをコミット含ま)
IonicăBizău

4
何もありませんclose()決して解決策があり、オブジェクト読み取り可能に?データ交換は常に不完全です...
CodeManX

71

編集:朗報!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');
    });

public関数ReadStream.destroyはドキュメント化されていませんが(Node.js v0.12.2)、GitHub2012年10月5日commit)でソースコードを確認できます。

destroyこの関数は、内部でマークしReadStream破壊されたとして、インスタンスを呼び出すとclose、ファイルを解放する機能を。

closeイベントをリッスンして、ファイルがいつ閉じられたかを正確に知ることができます。終了イベントは、データが完全に消費されていない限り発生しません。


destroy(およびclose)関数はfs.ReadStreamに固有であることに注意してください。一般的なstream判読可能な「インターフェース」の一部はありません。


少なくとも最新バージョンのノード(他のバージョンをチェックしていない)では、ファイル記述子は自動的に閉じられます。とは言っても、ストリームerrorが読み取られない場合にストリームが最終的に起動することを確認するための徹底的なテストは行っていません。それとは別に、私が心配している他の唯一のリークはイベントハンドラーです-もう一度、これについて100%確信はありませんが、2010年のアイザックの福音書ではハンドラーはエミッターがgc化された場合に剪定:groups.google.com/d/msg/nodejs/pXbJVo0NtaY/BxUmF_jp9LkJ
mikermcneil

1
データが小さすぎる場合、はon('data') 1回しかトリガーされないため、はなく.close()、他のユーザーに通知します。
bitfishxyz


12

できません。ノード5.3.0以降、一般的な読み取り可能ストリームを閉じる/シャットダウン/中止/破棄するための文書化された方法はありません。これは、ノードストリームアーキテクチャの制限です。

ここで他の回答が説明したように、fs.ReadStreamなど、Nodeによって提供されるReadableの特定の実装に対する文書化されていないハックがあります。これらは、Readableの一般的なソリューションではありません。

誰かがここで私を間違っていると証明できるなら、してください。私が不可能だと言っていることを実行できるようになりたいので、是正されてうれしいです。

編集:これは私の回避策でした:複雑な一連の呼び出しを介してパイプラインに実装.destroy()unpipe()ます。そして、そのすべての複雑さの後、それはすべての場合に適切に機能するわけはありません

編集:ノードv8.0.0は、destroy()読み取り可能なストリームのAPIを追加しました。


1
stream.pipeline「転送エラーと適切なクリーンアップを処理し、パイプラインが完了したときにコールバックを提供する」と主張するが今あります。それは役に立ちますか?
andrewdotn 2018

11

バージョン4.*.*でnull値をストリームにプッシュすると、EOFシグナルがトリガーされます。

nodejs docsから

null以外の値が渡された場合、push()メソッドは、後続のストリームプロセッサが消費するデータのチャンクをキューに追加します。nullが渡されると、ストリームの終わり(EOF)を通知し、その後、データを書き込むことができなくなります。

このページで他の多くのオプションを試した後、これは私にとってはうまくいきました。


1
私のために働く。しかし、私はnullをプッシュした後にdone()コールバックを呼び出さないようにして、予期された動作、つまりストリーム全体が停止することを回避する必要がありました。
リッチアポダカ2016

6

この破棄モジュールは、ストリームが確実に破棄され、さまざまなAPIとNode.jsバグを処理することを目的としています。今は最良の選択の一つです。

NB。ノード10以降では、この.destroyメソッドをさらに依存することなく使用できます。


3

でストリームをクリアして閉じることができますyourstream.resume()。これにより、ストリーム上のすべてがダンプされ、最終的には閉じられます。

公式ドキュメントから:

readible.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 2016

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
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.