目次
序文
「ストリーム」は、システムのキャッシュを処理する方法です。オペレーティング システムはデータをチャンク単位で読み取り、データを受信するたびにキャッシュに格納します。Node アプリケーションには 2 つのキャッシュ処理方法があります. 1 つ目は、すべてのデータが受信されるまで待機し、一度にキャッシュから読み取る方法です. これは、ファイルを読み取る従来の方法です. 2 つ目は、「データ ストリーム」方法を使用する方法です. . データのブロックが受信されると、1 つのブロックが読み取られます。つまり、データが受信されていない場合は、処理が開始されます。
最初の方法は、最初にすべてのデータをメモリに読み込んでから処理する方法です. 利点は、直感的でプロセスが非常に自然であることです. 欠点は、大きなファイルに遭遇した場合、時間がかかることです.データ処理ステップに入る。2 番目の方法では、「流れる水」のように、一度に小さなデータのみを読み取ります。システムが小さなデータを読み取るたびに、イベントがトリガーされ、「新しいデータ ブロック」信号が送信されます。アプリケーションがこのイベントをリッスンしている限り、データの読み取りの進行状況を把握して対応する処理を実行できるため、プログラムのパフォーマンスが向上します。
nodejs では、次のような多くの IO 処理オブジェクトが Steam インターフェイスでデプロイされます。
- ファイルの読み書き
- HTTP リクエストの読み取りと書き込み
- TCP 接続
- 標準入出力
ストリーム インターフェイスは、読み取り可能なデータ ストリーム、書き込み可能なデータ ストリーム、双方向データ ストリームの 3 つのカテゴリに分類できます。
可算ストリーム
読み取り可能
var Readable = require('stream').Readable;
var rs = new Readable();
rs.push('beep ');
rs.push('boop\n');
rs.push(null);
rs.pipe(process.stdout); // beep boop
読み取り可能なデータ ストリームには、ストリーミング状態と一時停止状態の 2 つの状態があります。
フロー状態はデータの送信を開始することを意味し、ポーズ状態はデータの送信が中断されることを意味します。
一時停止を流れに変える 4 つの方法
1.データイベントリスナー関数を追加
var fs = require('fs');
var readableStream = fs.createReadStream('url.js');
var data = '';
readableStream.setEncoding('utf8'); // 还处于暂停态
readableStream.on('data', function(chunk) {
data+=chunk;
}); // 从暂停态进入流动态,data开始被赋值
readableStream.on('end', function() {
console.log(data);
});
2.再開メソッドを呼び出す
var fs = require('fs');
var readable = fs.createReadStream('url.js'); // 暂停态
readable.resume(); // 强制从暂停态进入流动态
readable.on('end', function(chunk) {
console.log('数据流到达尾部,未读取任务数据');
});
3. pipe メソッドを呼び出して、書き込み可能なデータ ストリームにデータを送信します。
var fs = require("fs");
fs.createReadStream("url.js").pipe(process.stdout);
4. stream.read() を明示的に呼び出す
var fs = require('fs');
var readableStream = fs.createReadStream('url.js');
var data = '';
var chunk;
readableStream.setEncoding('utf8');
// readable事件表示系统缓冲之中有可读的数据,使用read方法去读出数据。如果没有数据可读,read方法会返回null。
readableStream.on('readable', function() {
while ((chunk=readableStream.read()) !== null) {
data += chunk;
}
});
readableStream.on('end', function() {
console.log(data)
});
フロー状態を一時停止状態に変更する方法は 2 つあります。
1.pipeメソッドの宛先がない場合はpauseメソッドを呼ぶ
var fs = require('fs');
var readableStream = fs.createReadStream('url.js');
readableStream.on('data', function(chunk) {
console.log('读取%d字节的数据', chunk.length);
readableStream.pause(); // 暂停了
console.log('接下来的1秒内不读取数据');
setTimeout(function() {
console.log('数据恢复读取');
readableStream.resume(); // 之后重新从暂停状态进入流动态
}, 1000);
});
2. パイプ メソッドの宛先が存在する場合、データ イベントのすべてのリスナー関数を削除し、unpipe メソッドを呼び出してすべてのパイプ メソッドの宛先を削除します。
var fs = require('fs');
var readableStream = fs.createReadStream('url.js');
readableStream.pipe(process.stdout);
setTimeout(function() {
console.log('停止写入url.js');
readableStream.unpipe(process.stdout); // 移除管道后,无法继续传送数据流,进入暂停态
}, 0);
読み取り可能なデータ ストリームの一般的なメソッドとプロパティ
読み取り可能なプロパティ
読み取り可能なストリームの読み取り可能なプロパティは、ブール値を返します。データ ストリームが読み取り可能なデータ ストリームの場合は true、そうでない場合は false を返します。
var fs = require('fs');
var readableStream = fs.createReadStream('url.js');
console.log(readableStream.readable) // true
read()
read メソッドは、システム キャッシュからデータを読み取って返します。データを読み取れない場合は null を返します。
var fs = require("fs");
var readableStream = fs.createReadStream("url.js");
readableStream.on("readable", function () {
var chunk;
while (null !== (chunk = readableStream.read())) {
console.log("got %d bytes of data", chunk.length);
}
});
_read()
読み取り可能なデータ ストリームの _read メソッドは、読み取り可能なデータ ストリームにデータを入れることができますが、このプロセスは続行され、停止しないと無限ループになります。
var Readable = require("stream").Readable;
var rs = Readable();
var count = 0;
rs._read = function () {
if (count < 10) {
rs.push(count + "dx ");
count++;
} else {
// null时,及默认为结束
rs.push(null);
}
};
rs.pipe(process.stdout); // 0dx 1dx 2dx 3dx 4dx 5dx 6dx 7dx 8dx 9dx
このメソッドをsetEncoding()
で呼び出すと、データ ストリームは、キャッシュ内のバイナリ オブジェクトではなく、指定されたエンコーディングの文字列を返します。たとえば、setEncoding('utf8') を呼び出すと、データ ストリームは UTF-8 文字列を返し、setEncoding('hex') を呼び出すと、データ ストリームは 16 進数の文字列を返します。
setEncoding のパラメータは、utf8、ascii、base64、buffer、hex など、文字列のエンコード方法です。
var Readable = require("stream").Readable;
var rs = Readable();
var count = 0;
rs._read = function () {
if (count < 2) {
rs.push(count + "dx ");
count++;
} else {
// null时,及默认为结束
rs.push(null);
}
};
// rs.setEncoding('hex')
// rs.pipe(process.stdout); // 3064782031647820
rs.setEncoding('utf8')
rs.pipe(process.stdout); // 0dx 1dx
resume() および pause()
resume メソッドは、「読み取り可能なデータ ストリーム」が引き続きデータ イベントを解放するようにします。つまり、動的なストリームに変わります。
一時停止メソッドは、動的データ ストリームがデータ イベントの解放を停止し、一時停止状態になるようにします。この時点ですでに読み取り可能なデータは、システム キャッシュに残ります。
var fs = require('fs');
var readableStream = fs.createReadStream('url.js');
readableStream.on('data', function(chunk) {
console.log('读取%d字节的数据', chunk.length);
readableStream.pause(); // 暂停了
console.log('接下来的1秒内不读取数据');
setTimeout(function() {
console.log('数据恢复读取');
readableStream.resume(); // 之后重新从暂停状态进入流动态
}, 1000);
});
isPaused()
このメソッドは、「読み取り可能なデータ ストリーム」がクライアントによって手動で一時停止されたこと (つまり、pause メソッドが呼び出されたこと) を示すブール値を返します。
var readable = require("stream").Readable()
console.log(readable.isPaused()) // === false
readable.pause()
console.log(readable.isPaused()) // === true
readable.resume()
console.log(readable.isPaused()) // === false
pipe() と unpipe()
pipe メソッドは、パイプのように自動的にデータを転送する仕組みです。「読み取り可能なデータストリーム」からすべてのデータを読み取り、指定された宛先に書き込みます。全体のプロセスは自動です。
unpipe メソッドは、pipe メソッドで指定されたストリームの宛先を削除します。引数がない場合、すべてのパイプ メソッドの宛先を削除します。引数がある場合は、引数で指定された宛先を削除します。引数に一致する宛先がない場合、効果はありません。
url.js ファイルは、次の方法でコピーできます。
var fs = require('fs');
var readableStream = fs.createReadStream('url.js');
var writableStream = fs.createWriteStream('url1.js');
// pipe方法必须在可读数据流上调用,它的参数必须是可写数据流。
readableStream.pipe(writableStream);
var fs = require('fs');
var zlib = require('zlib');
fs.createReadStream('url.js')
.pipe(zlib.createGunzip())
.pipe(fs.createWriteStream('url1.js'));
上記のコードは、チェーン書き込み方式を採用しており、最初にファイルを読み取り、次に圧縮し、最後に出力します。
var fs = require("fs");
var readable = fs.createReadStream("url.js");
var writable = fs.createWriteStream("url1.js");
readable.pipe(writable);
setTimeout(function () {
console.log("停止写入url1.js");
readable.unpipe(writable);
console.log("手动关闭url1.js的写入数据流");
writable.end();
}, 1);
読み取り可能なデータ ストリームをリッスンするイベント
主にデータ読み取り終了クローズエラーの5つのイベント
- 読み取り可能なイベントは、データ ストリームが外部にデータを提供できる場合にトリガーされます。
- 明示的に一時停止されていないデータ ストリームの場合、データ イベント リスニング関数を追加すると、データ ストリームがストリーム ダイナミクスに切り替えられ、できるだけ早くデータが提供されます。
- データを読み取ることができなくなると、終了イベントがトリガーされます。
- close イベントは、データ ソースが閉じられるときに発生します。すべてのストリームがこのイベントをサポートしているわけではありません。
- データの読み取り中にエラーが発生すると、エラー イベントがトリガーされます。
前の例では、読み取り可能なデータ エンドが実際に使用されており、クローズとエラーを確認します。
近い
var fs = require("fs");
var readable = fs.createReadStream("url.js");
readable.resume(); // 开始读取数据
readable.on("close", function () {
console.log("数据源关闭"); // 当数据源被读取完毕,数据源关闭时触发
});
エラー
var fs = require("fs");
var readable = fs.createReadStream("url2.js"); // url2不存在,会报错
readable.resume(); // 开始读取数据
readable.on("error", function (error) {
console.log(error); // no such file or directory, open 'D:\Codes\Test\url2.js'....
console.log("url2不存在"); // url2不存在
});
書き込み可能なデータ ストリーム
- クライアント http リクエスト
http.request(options, (res) => {
}
- サーバーの http 応答
var server = http.createServer(function (req, res) {
}
- fs 書き込みストリーム
var writableStream = fs.createWriteStream('file2.txt');
- zlib ストリーム
zlib.createGzip()
- 暗号ストリーム
const crypto = require('crypto');
const cipher = crypto.createCipher('aes192', 'a password');
let encrypted = '';
cipher.on('readable', () => {
const data = cipher.read();
if (data)
encrypted += data.toString('hex');
});
cipher.on('end', () => {
console.log(encrypted);
// Prints: ca981be48e90867604588e75d04feabb63cc007a8f8ad89b10616ed84d815504
});
cipher.write('some clear text data');
cipher.end();
- TCP ソケット
const net = require('net');
const server = net.createServer((c) => {
// 'connection' listener
console.log('client connected');
c.on('end', () => {
console.log('client disconnected');
});
c.write('hello\r\n');
c.pipe(c);
});
- 子プロセス標準入力
- process.stdout、process.stderr
fs.createReadStream("url.js").pipe(process.stdout)
書き込み可能なデータ ストリームのメソッドとプロパティ
writable プロパティ
writable プロパティはブール値を返します。データ ストリームがまだ開いていて書き込み可能な場合は true を返し、それ以外の場合は false を返します。
var fs = require("fs");
var writableStream = fs.createWriteStream('url1.js');
console.log(writableStream.writable) // true
write()
2 つのパラメーターを受け入れます。1 つは書き込まれるコンテンツで、文字列、ストリーム オブジェクト (読み取り可能なデータ ストリームなど)、またはバッファー オブジェクト (バイナリ データを表す) であり、もう 1 つは書き込み後のものです。完成したコールバック関数です
。オプションです。もちろん、2 番目のパラメータはエンコード方法の文字列を渡すこともできます。
var fs = require("fs");
var writableStream = fs.createWriteStream("url1.txt");
// writableStream.write("dx ", function () {
// console.log("已经写入了dx");
// });
writableStream.write("dx1 ", "ascii");
writableStream.end("yx\n");
cork()、uncork()
cork メソッドは、待機中のデータを強制的にキャッシュに書き込むことができます。
uncork メソッドまたは end メソッドが呼び出されると、キャッシュされたデータが吐き出されます。
var fs = require("fs");
var stream = fs.createWriteStream("url1.txt");;
stream.cork();
stream.write('some ');
stream.write('data ');
process.nextTick(() => stream.uncork());
setDefaultEncoding()
setDefaultEncoding メソッドは、書き込まれたデータを新しい形式にエンコードするために使用されます。
var fs = require("fs");
var writableStream = fs.createWriteStream("url1.js");
writableStream.write("dx1 ");
writableStream.setDefaultEncoding("base64url");
writableStream.write("yx"); // yx将会以base64url的方式写入
end()
end メソッドは、「書き込み可能なデータ ストリーム」を終了するために使用されます。このメソッドは 3 つのパラメーターを受け入れますが、これらはすべてオプションです。
最初のパラメータは最後に書き込まれるデータで、文字列、ストリーム オブジェクト、またはバッファ オブジェクトのいずれかです。2 番目のパラメータは
書き込みコードです。3
番目のパラメータはコールバック関数です。終了イベントが発生すると、このコールバック関数をトリガーします。
var fs = require("fs");
var writableStream = fs.createWriteStream("url1.js");
writableStream.write("dx1 ");
writableStream.end("yx1",'ascii',function() {
console.log('写入结束了')
});
書き込み可能なストリームのイベント
ドレイン イベント
writable.write(chunk) が false を返した後、キャッシュされたすべてのデータが書き込まれ、引き続き書き込み可能になると、ドレイン イベントがトリガーされ、キャッシュが空であることを示します。
var fs = require("fs");
var writableStream = fs.createWriteStream("url1.js");
function writeOneMillionTimes(writer, data, encoding, callback) {
var i = 1000000;
write();
function write() {
var ok = true;
do {
i -= 1;
if (i === 0) {
writer.write(data, encoding, callback);
} else {
ok = writer.write(data, encoding);
}
} while (i > 0 && ok);
if (i > 0) {
writer.once('drain',function(){
console.log(i)
});
}
}
}
writeOneMillionTimes(writableStream,'write1','utf-8',function(){
// console.log()
})
終了イベント
end メソッドが呼び出されると、キャッシュされたすべてのデータが解放され、終了イベントがトリガーされます。
var fs = require("fs");
var writableStream = fs.createWriteStream("url1.js");
writableStream.write("dx1 ");
writableStream.end("yx1",'ascii',function() {
console.log('写入结束了')
});
writableStream.on('finish',function(){
console.log('end调用了,完成了')
})
Pipe イベントと unpipe イベント
これはよくわかりますが、pipe() 呼び出しがあると pipe イベントリスナーがトリガーされ、unpipe() 呼び出しがあると unpipe イベントリスナーがトリガーされます。
var fs = require("fs");
var readable = fs.createReadStream("url.js");
var writable = fs.createWriteStream("url1.js");
writable.on("pipe", function () {
console.log("pipe触发了");
});
writable.on("unpipe", function () {
console.log("unpipe触发了");
});
readable.pipe(writable);
setTimeout(function () {
console.log("停止写入url1.js");
readable.unpipe(writable);
console.log("手动关闭url1.js的写入数据流");
writable.end();
}, 1);
エラー イベント
このイベントは、データの書き込みまたはパイプラインの使用中にエラーが発生したときにトリガーされます。イベントが発生すると、コールバック関数は Error パラメータのみを受け取ります。
エラー処理
完了した
コマンド ライン インストールで追加のパッケージを呼び出す必要がある
npm install on-finished
以下を実行すると、ストリーム自体のエラーを解決できるだけでなく、
クライアントによって書き込まれたデータ ストリームがダウンロードを中断して close イベントを受け取り、待機し続けてメモリ リークが発生するのを防ぐことができます。
var onFinished = require("on-finished");
var http = require("http");
http.createServer(function (req, res) {
// set the content headers
var stream = fs.createReadStream("filename.txt");
stream
.on("error", onerror)
.pipe(zlib.createGzip())
.on("error", onerror)
.pipe(res);
function onerror(err) {
console.error(err.stack);
// 彻底关闭这次的stream
stream.destroy();
}
onFinished(res, function () {
// make sure the stream is always destroyed
stream.destroy();
});
});
nodejsに関連するその他のコンテンツ
nodejs commonjs を導入
nodejs fs モジュールを導入
nodejs パス モジュールを導入
nodejs イベント モジュールを導入
nodejs http モジュールを導入
nodejs net モジュールを導入
nodejs url モジュールを導入
nodejs プロセス モジュールを導入
nodejs バッファ モジュールを導入