78

私はnode.jsをいじっていて、ファイルが存在することを確認し、writeHeadで適切なMIMEタイプを送信したら、ファイルを読み取ってネットワークに送信する2つの方法を発見しました。

// read the entire file into memory and then spit it out

fs.readFile(filename, function(err, data){
  if (err) throw err;
  response.write(data, 'utf8');
  response.end();
});

// read and pass the file as a stream of chunks

fs.createReadStream(filename, {
  'flags': 'r',
  'encoding': 'binary',
  'mode': 0666,
  'bufferSize': 4 * 1024
}).addListener( "data", function(chunk) {
  response.write(chunk, 'binary');
}).addListener( "close",function() {
  response.end();
});

問題のファイルがビデオのように大きなものである場合、 fs.createReadStream がより良いユーザーエクスペリエンスを提供する可能性があると仮定するのは正しいですか? ブロックっぽさが減ったような気がします。これは本当ですか?私が知る必要がある他の長所、短所、注意事項、または落とし穴はありますか?

4

4 に答える 4

62

「data」を「write()」に接続し、「close」を「end()」に接続する場合のより良いアプローチ:

// 0.3.x style
fs.createReadStream(filename, {
  'bufferSize': 4 * 1024
}).pipe(response)

// 0.2.x style
sys.pump(fs.createReadStream(filename, {
  'bufferSize': 4 * 1024
}), response)

read.pipe(write)orsys.pump(read, write)アプローチには、フロー制御も追加できるという利点があります。したがって、書き込みストリームがデータをすぐに受け入れることができない場合は、メモリにバッファリングされるデータの量を最小限に抑えるために、読み取りストリームにバックオフするように指示します。

flags:"r"とはmode:0666、それがであるという事実によって暗示されFileReadStreamます。エンコーディングは非推奨です。binaryエンコーディングが指定されていない場合は、生データバッファでのみ機能します。

また、ファイルを非常に滑らかにする他の機能を追加することもできます。

  1. をスニッフィングしてreq.headers.range、のような文字列と一致するかどうかを確認します/bytes=([0-9]+)-([0-9]+)/。その場合は、その開始位置から終了位置までストリーミングするだけです。(番号がない場合は、0または「終わり」を意味します。)
  2. stat()呼び出しからのiノードと作成時間をETagヘッダーにハッシュします。「if-none-match」がそのヘッダーと一致するリクエストヘッダーを取得した場合は、を返送して304 Not Modifiedください。
  3. if-modified-sinceヘッダーをmtime統計オブジェクトの日付と照合します。指定された日付以降に変更されていない場合は304。

また、一般的に、可能であれば、Content-Lengthヘッダーを送信します。(statファイルを作成しているので、これが必要です。)

于 2011-01-04T07:07:07.117 に答える
45

fs.readFileあなたが指摘したようにファイル全体をメモリにロードし、fs.createReadStream指定したサイズのチャンクでファイルを読み取ります。

fs.createReadStreamまた、クライアントは、データが読み取られるときにチャンクで送信されるため、データの受信をより高速に開始します。一方fs.readFile、ファイル全体を読み取り、それからクライアントへの送信を開始します。これは無視できるかもしれませんが、ファイルが非常に大きく、ディスクが遅い場合は違いが生じる可能性があります。

ただし、これら2つの関数を100MBのファイルで実行する場合、最初の関数は100MBのメモリを使用してファイルをロードしますが、後者は最大4KBしか使用しません。

fs.readFile編集:大きなファイルを開くと言っていたので、特に使用する理由はわかりません。

于 2011-01-04T04:28:45.817 に答える
0

もう 1 つ、おそらくあまり知られていないことですが、Node.js はfs.readFileと比較して、使用後の未使用メモリのクリーンアップに優れていると私は信じていfs.createReadStreamます。これをテストして、何が最適かを確認する必要があります。また、Node のバージョンが新しくなるたびに、これが改善されていることも知っています (つまり、ガベージ コレクターは、この種の状況でより賢くなっています)。

于 2012-08-30T18:31:25.520 に答える