1。オープニング分析
ストリームは、ノード内の多くのオブジェクトによって実装された抽象インターフェイスです。たとえば、HTTPサーバーへのリクエストはストリームであり、STDOUTもストリームです。ストリームは読みやすく、書くか、その両方です。
ストリームとの最初の接触は、初期のUnixから始まりました。数十年にわたる実践により、Streamのアイデアは単にいくつかの巨大なシステムを開発できることが証明されています。
UNIXでは、ストリームは「|」を通じて実装されます。ノードでは、組み込みのストリームモジュールとして、多くのコアモジュールと3つのパーティモジュールが使用されています。
UNIXと同様に、ノードストリームの主な動作は.pipe()であり、ユーザーは逆圧力メカニズムを使用して読み取りと書き込みのバランスを制御できます。
Streamは、開発者に、抽象ストリームインターフェイスを介してストリーム間の読み取りおよび書き込みバランスを再利用および制御できる統一インターフェイスを提供できます。
TCP接続は読み取り可能なストリームと書き込み可能なストリームの両方であり、HTTP接続は異なります。 HTTPリクエストオブジェクトは読み取り可能なストリームであり、HTTP応答オブジェクトは書き込み可能なストリームです。
ストリームトランスミッションプロセスは、他のエンコードフォームを設定しない限り、デフォルトでバッファーの形式で送信されます。以下は例です。
コードコピーは次のとおりです。
var http = require( 'http');
var server = http.createserver(function(req、res){
Res.WriteHeader(200、{'Content-Type': 'Text/Plain'});
res.End( "Hello、Big Bear!");
});
server.listen(8888);
console.log( "ポート8888で実行されているhttpサーバー...");
実行後、指定された文字セットが「UTF-8」などの設定されていないため、Garled Codeが表示されます。
変更するだけです:
コードコピーは次のとおりです。
var http = require( 'http');
var server = http.createserver(function(req、res){
Res.WriteHeader(200、{
'content-type': 'text/plain; charset = utf-8' // charset = utf-8を追加します
});
res.End( "Hello、Big Bear!");
});
server.listen(8888);
console.log( "ポート8888で実行されているhttpサーバー...");
実行結果:
ストリームを使用する理由
ノード内のI/Oは非同期であるため、ディスクとネットワークへの読み取りと書き込みには、コールバック関数を介してデータを読み取り、読み取りする必要があります。以下は、ファイルのダウンロードの例です
コード:
コードコピーは次のとおりです。
var http = require( 'http');
var fs = require( 'fs');
var server = http.createserver(function(req、res){
fs.readfile(__ dirname + '/data.txt'、function(err、data){
res.End(data);
});
});
server.listen(8888);
コードは必要な機能を実装できますが、サービスはファイルデータを送信する前にファイルデータ全体をメモリにキャッシュする必要があります。 「data.txt」ファイルが非常にある場合
それが大きく、大きな並行性がある場合、多くの記憶が無駄になります。ユーザーは、ファイル全体がメモリにキャッシュされるまで待機する必要があるため、ファイルデータを受け入れる必要があるため、これは
ユーザーエクスペリエンスは非常に悪いです。幸いなことに、両方のパラメーター(req、res)はストリームであるため、fs.readfile()の代わりにfs.createreadstream()を使用できます。次のように:
コードコピーは次のとおりです。
var http = require( 'http');
var fs = require( 'fs');
var server = http.createserver(function(req、res){
var stream = fseatereadstream(__ dirname + '/data.txt');
stream.pipe(res);
});
server.listen(8888);
.pipe()メソッドは、fs.createreadStream()の「データ」および「終了」イベントを聴いているため、「data.txt」ファイルをキャッシュする必要はありません。
クライアント接続が完了した直後に、ファイルをクライアントに送信できます。 .pipe()を使用するもう1つの利点は、顧客が解決できることです。
非常に大きなエンド遅延によって引き起こされる不均衡を読み取り、書き込みます。
5つの基本的なストリームがあります:読み取り可能、書き込み、変換、デュプレックス、「クラシック」。 (詳細についてはAPIを確認してください)
2。例を紹介します
処理する必要があるデータを一度にメモリにロードできない場合、または読み取り中に処理がより効率的になる場合は、データストリームを使用する必要があります。 nodejsは、さまざまなストリームを介してデータストリームの操作を提供します。
大規模なファイルコピープログラムを例にとると、データソースの読み取り専用データストリームを作成できます。例は次のとおりです。
コードコピーは次のとおりです。
var rs = fs.createreadstream(pathname);
rs.on( 'data'、function(chunk){
DOSOMTHING(Chunk); //必要に応じて特定の詳細を使用します
});
rs.on( 'end'、function(){
掃除() ;
});
コード内のデータイベントは、関数が処理できるかどうかにかかわらず、継続的にトリガーされます。この問題を解決するために、コードを次のように変更できます。
コードコピーは次のとおりです。
var rs = fs.createreadstream(src);
rs.on( 'data'、function(chunk){
rs.Pause();
dosomthing(chunk、function(){
rs.resume();
});
});
rs.on( 'end'、function(){
掃除();
});
コールバックがdosomething関数に追加されるため、データを処理する前にデータの読み取りを一時停止し、データを処理した後もデータを読み続けることができます。
さらに、次のように、データターゲットの書き込み専用データストリームを作成することもできます。
コードコピーは次のとおりです。
var rs = fs.createreadstream(src);
var ws = fs.createwritestream(dst);
rs.on( 'data'、function(chunk){
ws.write(chunk);
});
rs.on( 'end'、function(){
ws.end();
});
DosomThingがWriteのみのストリームにデータを書き込んで置き換えられた後、上記のコードはファイルコピープログラムのように見えます。ただし、上記のコードには上記の問題があります。書き込み速度が読み取り速度に追いつくことができない場合、データストリーム内にキャッシュを書き込むだけが爆発します。着信データがターゲットに書き込まれているか、.writeメソッドの返品値に基づいてキャッシュに一時的に配置されているかどうかを判断し、排水イベントに基づいてターゲットに書き込みデータのみがターゲットに書き込まれ、次のデータに渡された場合に判断できます。したがって、コードは次のとおりです。
コードコピーは次のとおりです。
var rs = fs.createreadstream(src);
var ws = fs.createwritestream(dst);
rs.on( 'data'、function(chunk){
if(ws.write(chunk)=== false){
rs.Pause();
}
});
rs.on( 'end'、function(){
ws.end();
});
ws.on( 'Drane'、function(){
rs.resume();
});
最後に、読み取り専用のデータストリームから書き込み専用のデータストリームへのデータ転送が実現され、爆発防止倉庫制御が含まれています。上記の大規模なファイルコピープログラムなど、多くの使用法シナリオがあるため、NodeJSはこれを行うための.Pipeメソッドを直接提供し、その内部実装方法は上記のコードに似ています。
ファイルをコピーするためのより完全なプロセスを次に示します。
コードコピーは次のとおりです。
var fs = require( 'fs')、
パス= require( 'path')、
out = process.stdout;
var filepath = '/bb/bigbear.mkv';
var readstream = fs.createreadstream(filepath);
var writeStream = fs.createwritestream( 'file.mkv');
var stat = fs.statsync(filepath);
var totalize = stat.size;
var passedlength = 0;
var lastsize = 0;
var starttime = date.now();
readstream.on( 'data'、function(chunk){
passedlength += chunk.length;
if(writestream.write(chunk)=== false){
readstream.pause();
}
});
readstream.on( 'end'、function(){
writestream.end();
});
writestream.on( 'Drane'、function(){
readstream.resume();
});
setimeout(function show(){
varパーセント= math.ceil((passedlength / totalsize) * 100);
var size = math.ceil(passedlength / 1000000);
var diff = size- lastsize;
lastsize = size;
out.clearline();
out.cursorto(0);
out.write( '完了' + size + 'mb、' +パーセント + '%、速度:' + diff * 2 + 'mb/s');
if(passedlength <totalize){
Settimeout(Show、500);
} それ以外 {
var endtime = date.now();
console.log();
console.log( '共有の場合:' +(endtime -starttime) / 1000 + '秒。');
}
}、500);
上記のコードを「copy.js」として保存できます。実験:再帰的なSetimeout(またはSetIntervalを直接使用)して傍観者にしました。
500msごとに完了の進行状況を観察し、完了したサイズ、パーセンテージ、コピー速度をコンソールに書き込みます。コピーが完了すると、合計時間が計算されます。
3つ、要約しましょう
(1)ストリームの概念を理解する。
(2)関連するストリームAPIの使用に習熟しています
(3)以下などの詳細の制御に注意を払ってください。シャードに「チャンクデータ」の形式を使用して、大規模なファイルをコピーします。
(4)、パイプの使用
(5)、概念を再度強調します。TCP接続は読み取り可能なストリームと書き込み可能なストリームの両方であり、HTTP接続は異なります。 HTTPリクエストオブジェクトは読み取り可能なストリームであり、HTTP応答オブジェクトは書き込み可能なストリームです。