序章
コンピューティングにおけるストリームの概念は、通常、安定した連続的なフローでのデータの配信を表します。 ソースからの読み取りまたはソースへの書き込みにストリームを継続的に使用できるため、すべてのデータを一度にメモリに収める必要がなくなります。
ストリームを使用すると、2つの大きな利点があります。 1つは、処理を開始する前にすべてのデータをメモリにロードする必要がないため、メモリを効率的に使用できることです。 もう1つの利点は、ストリームの使用が時間効率に優れていることです。 ペイロード全体を待つのではなく、ほぼすぐにデータの処理を開始できます。 これらの利点により、ストリームはI/O操作での大規模なデータ転送に適したツールになります。 ファイルは、いくつかのデータを含むバイトのコレクションです。 ファイルはNode.jsの一般的なデータソースであるため、ストリームはNode.jsのファイルを効率的に操作する方法を提供します。
Node.jsは、ストリーミングAPIを提供します stream
モジュール、ストリームを操作するためのコアNode.jsモジュール。 すべてのNode.jsストリームは、 EventEmitter
クラス(詳細については、 Node.js でのイベントエミッターの使用を参照してください)。 これらは、データ送信プロセス中にさまざまな間隔でリッスンできるさまざまなイベントを発行します。 ネイティブ stream
モジュールは、データの読み取りと書き込み、伝送ライフサイクルの管理、および伝送エラーの処理に使用できるイベントをリッスンするためのさまざまな機能で構成されるインターフェイスを提供します。
Node.jsには4種類のストリームがあります。 彼らです:
- 読み取り可能なストリーム:データを読み取ることができるストリーム。
- 書き込み可能なストリーム:データを書き込むことができるストリーム。
- デュプレックスストリーム:読み取りと書き込みが可能なストリーム(通常は同時に)。
- 変換ストリーム:出力(または書き込み可能なストリーム)が入力(または読み取り可能なストリーム)の変更に依存しているデュプレックスストリーム。
ファイルシステムモジュール(fs
)は、ファイルを操作し、一般的にローカルファイルシステムをナビゲートするためのネイティブNode.jsモジュールです。 これを行うためのいくつかの方法を提供します。 これらのメソッドのうちの2つは、ストリーミングAPIを実装します。 これらは、ストリームを使用してファイルを読み書きするためのインターフェイスを提供します。 これらの2つの方法を使用して、読み取りおよび書き込み可能なファイルストリームを作成できます。
この記事では、を使用してファイルの読み取りと書き込みを行います。 fs.createReadStream
と fs.createWriteStream
機能。 また、あるストリームの出力を別のストリームの入力として使用し、カスタム変換スチームを実装します。 これらのアクションを実行することで、ストリームを使用してNode.jsのファイルを操作する方法を学びます。 これらの概念を示すために、コマンドラインプログラムを作成して、 cat
Linuxベースのシステムに見られる機能、端末からファイルへの入力の書き込み、ファイルのコピー、およびファイルのコンテンツの変換。
前提条件
このチュートリアルを完了するには、次のものが必要です。
- 開発マシンにインストールされているNode.js。 このチュートリアルでは、バージョン14.10.0を使用します。 さまざまなプラットフォームへのインストールについては、チュートリアルシリーズNode.jsをインストールしてローカル開発環境を作成する方法を参照してください。
- 私たちのシリーズNode.jsでコーディングする方法で見つけることができるNode.jsの基本的な知識。
- Node.jsの基本的な知識
fs
モジュール。Node.jsのfsモジュールを使用してファイルを操作する方法にあります。
ステップ1—ファイル処理コマンドラインプログラムの設定
このステップでは、基本的なコマンドを使用してコマンドラインプログラムを作成します。 このコマンドラインプログラムは、チュートリアルの後半で学習する概念を示します。ここでは、ファイルを操作するために作成する関数でこれらのコマンドを使用します。
まず、このプログラムのすべてのファイルを含むフォルダーを作成します。 ターミナルで、という名前のフォルダを作成します node-file-streams
:
- mkdir node-file-streams
を使用して cd
コマンドを実行し、作業ディレクトリを新しいフォルダに変更します。
- cd node-file-streams
次に、というファイルを作成して開きます mycliprogram
お気に入りのテキストエディタで。 このチュートリアルではGNUを使用します nano
、ターミナルテキストエディタ。 nanoを使用してファイルを作成して開くには、次のコマンドを入力します。
- nano mycliprogram
テキストエディタで、次のコードを追加してshebangを指定し、Node.jsプロセスからのコマンドライン引数の配列を格納し、アプリケーションに必要なコマンドのリストを格納します。
#!/usr/bin/env node
const args = process.argv;
const commands = ['read', 'write', 'copy', 'reverse'];
最初の行には、プログラムインタープリターへのパスであるシバンが含まれています。 この行を追加すると、プログラムローダーはNode.jsを使用してこのプログラムを解析するようになります。
コマンドラインでNode.jsスクリプトを実行すると、Node.jsプロセスの実行時にいくつかのコマンドライン引数が渡されます。 これらの引数には、 argv
プロパティまたはNode.js process
. The argv
プロパティは、Node.jsスクリプトに渡されるコマンドライン引数を含む配列です。 2行目では、そのプロパティをという変数に割り当てます。 args
.
次に、 getHelpText
プログラムの使用方法のマニュアルを表示する機能。 以下のコードを mycliprogram
ファイル:
...
const getHelpText = function() {
const helpText = `
simplecli is a simple cli program to demonstrate how to handle files using streams.
usage:
mycliprogram <command> <path_to_file>
<command> can be:
read: Print a file's contents to the terminal
write: Write a message from the terminal to a file
copy: Create a copy of a file in the current directory
reverse: Reverse the content of a file and save its output to another file.
<path_to_file> is the path to the file you want to work with.
`;
console.log(helpText);
}
The getHelpText
functionは、プログラムのヘルプテキストとして作成した複数行の文字列を出力します。 ヘルプテキストには、プログラムが期待するコマンドライン引数またはパラメータが表示されます。
次に、制御ロジックを追加して、 args
適切な応答を提供します。
...
let command = '';
if(args.length < 3) {
getHelpText();
return;
}
else if(args.length > 4) {
console.log('More arguments provided than expected');
getHelpText();
return;
}
else {
command = args[2]
if(!args[3]) {
console.log('This tool requires at least one path to a file');
getHelpText();
return;
}
}
上記のコードスニペットでは、空の文字列を作成しました command
端末から受信したコマンドを保存します。 最初 if
ブロックは、の長さが args
配列は3未満です。 3未満の場合は、プログラムの実行時に他の追加の引数が渡されなかったことを意味します。 この場合、ヘルプテキストを端末に出力して終了します。
The else if
ブロックは、の長さが args
配列が4より大きい。 そうである場合、プログラムは必要以上の引数を受け取りました。 プログラムは、ヘルプテキストとともにこの趣旨のメッセージを出力して終了します。
最後に、 else
ブロックでは、3番目の要素または要素をの2番目のインデックスに格納します args
の配列 command
変数。 このコードは、4番目の要素またはインデックス=3の要素が args
配列。 アイテムが存在しない場合は、続行するにはファイルパスが必要であることを示すメッセージが端末に出力されます。
ファイルを保存します。 次に、アプリケーションを実行します。
- ./mycliprogram
あなたは得るかもしれません permission denied
以下の出力と同様のエラー:
Output-bash: ./mycliprogram: Permission denied
このエラーを修正するには、ファイルに実行権限を付与する必要があります。これは、次のコマンドで実行できます。
- chmod +x mycliprogram
ファイルを再実行してください。 出力は次のようになります。
Outputsimplecli is a simple cli program to demonstrate how to handle files using streams.
usage:
mycliprogram <command> <path_to_file>
read: Print a file's contents to the terminal
write: Write a message from the terminal to a file
copy: Create a copy of a file in the current directory
reverse: Reverse the content of a file and save it output to another file.
最後に、コマンドを部分的に実装します。 commands
以前に作成したアレイ。 を開きます mycliprogram
ファイルを作成し、以下のコードを追加します。
...
switch(commands.indexOf(command)) {
case 0:
console.log('command is read');
break;
case 1:
console.log('command is write');
break;
case 2:
console.log('command is copy');
break;
case 3:
console.log('command is reverse');
break;
default:
console.log('You entered a wrong command. See help text below for supported functions');
getHelpText();
return;
}
switchステートメントで見つかったコマンドを入力するたびに、プログラムはそのコマンドに適切なcaseブロックを実行します。 この部分的な実装では、コマンドの名前を端末に出力します。 文字列が上記で作成したコマンドのリストにない場合、プログラムはヘルプテキストとともにその旨のメッセージを出力します。 その後、プログラムは終了します。
ファイルを保存してから、 read
コマンドと任意のファイル名:
- ./mycliprogram read test.txt
出力は次のようになります。
Outputcommand is read
これで、コマンドラインプログラムが正常に作成されました。 次のセクションでは、 cat
としての機能 read
を使用してアプリケーションでコマンド createReadStream()
.
ステップ2—でファイルを読む createReadStream()
The read
コマンドラインアプリケーションのコマンドは、ファイルシステムからファイルを読み取り、次のように端末に出力します。 cat
Linuxベースのターミナルでのコマンド。 このセクションでは、を使用してその機能を実装します createReadStream()
から fs
モジュール。
The createReadStream
関数は、から継承するため、聞くことができるイベントを発行する読み取り可能なストリームを作成します EventsEmitter
クラス。 The data
イベントはこれらのイベントの1つです。 読み取り可能なストリームがデータの一部を読み取るたびに、読み取り可能なストリームは data
イベント、データの一部をリリースします。 コールバック関数と一緒に使用すると、そのデータまたはまたは chunk
、およびそのコールバック関数内でそのデータを処理できます。 この場合、そのチャンクをターミナルに表示します。
まず、簡単にアクセスできるように、作業ディレクトリにテキストファイルを追加します。 このセクションとそれに続くいくつかのセクションでは、次のファイルを使用します。 lorem-ipsum.txt
. これは、 Lorem Ipsum Generator を使用して生成された約1200行のloremipsumテキストを含むテキストファイルであり、GitHubでホストされます。 ターミナルで、次のコマンドを入力して、ファイルを作業ディレクトリにダウンロードします。
- wget https://raw.githubusercontent.com/do-community/node-file-streams/999e66a11cd04bc59843a9c129da759c1c515faf/lorem-ipsum.txt
複製するには cat
コマンドラインアプリケーションの機能をインポートするには、 fs
モジュールが含まれているため createReadStream
必要な機能。 これを行うには、 mycliprogram
ファイルを作成し、シバンの直後にこの行を追加します。
#!/usr/bin/env node
const fs = require('fs');
次に、以下の関数を作成します switch
と呼ばれるステートメント read()
単一のパラメータを使用:読み取りたいファイルのファイルパス。 この関数は、そのファイルから読み取り可能なストリームを作成し、 data
そのストリームのイベント。
...
function read(filePath) {
const readableStream = fs.createReadStream(filePath);
readableStream.on('error', function (error) {
console.log(`error: ${error.message}`);
})
readableStream.on('data', (chunk) => {
console.log(chunk);
})
}
コードはまた、リッスンすることによってエラーをチェックします error
イベント。 エラーが発生すると、エラーメッセージが端末に出力されます。
最後に、交換する必要があります console.log()
とともに read()
最初のケースのブロックで機能する case 0
以下のコードブロックに示すように:
...
switch (command){
case 0:
read(args[3]);
break;
...
}
ファイルを保存して新しい変更を保持し、プログラムを実行します。
- ./mycliprogram read lorem-ipsum.txt
出力は次のようになります。
Output<Buffer 0a 0a 4c 6f 72 65 6d 20 69 70 73 75 6d 20 64 6f 6c 6f 72 20 73 69 74 20 61 6d 65 74 2c 20 63 6f 6e 73 65 63 74 65 74 75 72 20 61 64 69 70 69 73 63 69 ... >
...
<Buffer 76 69 74 61 65 20 61 6e 74 65 20 66 61 63 69 6c 69 73 69 73 20 6d 61 78 69 6d 75 73 20 75 74 20 69 64 20 73 61 70 69 65 6e 2e 20 50 65 6c 6c 65 6e 74 ... >
上記の出力に基づいて、データがチャンクまたはピースで読み取られたことがわかります。これらのデータは、 Buffer
タイプ。 簡潔にするために、上記の端末出力には2つのチャンクのみが表示され、省略記号は、ここに表示されているチャンクの間にいくつかのバッファーがあることを示しています。 ファイルが大きいほど、バッファーまたはチャンクの数が多くなります。
人間が読める形式でデータを返すには、2番目の引数として必要なエンコードタイプの文字列値をに渡すことにより、データのエンコードタイプを設定します。 createReadStream()
関数。 の2番目の引数では createReadStream()
関数、次の強調表示されたコードを追加して、エンコードタイプをに設定します utf8
.
...
const readableStream = fs.createReadStream(filePath, 'utf8')
...
プログラムを再実行すると、ターミナルにファイルの内容が表示されます。 プログラムは、からloremipsumテキストを出力します。 lorem-ipsum.txt
ファイルに表示されるとおりに1行ずつファイルします。
OutputLorem ipsum dolor sit amet, consectetur adipiscing elit. Aenean est tortor, eleifend et enim vitae, mattis condimentum elit. In dictum ex turpis, ac rutrum libero tempus sed...
...
...Quisque nisi diam, viverra vel aliquam nec, aliquet ut nisi. Nullam convallis dictum nisi quis hendrerit. Maecenas venenatis lorem id faucibus venenatis. Suspendisse sodales, tortor ut condimentum fringilla, turpis erat venenatis justo, lobortis egestas massa massa sed magna. Phasellus in enim vel ante viverra ultricies.
上記の出力は、端末に印刷されたファイルの内容のごく一部を示しています。 端子出力をと比較すると lorem-ipsum.txt
ファイルの場合と同様に、コンテンツがファイルと同じで、同じフォーマットを使用していることがわかります。 cat
指図。
このセクションでは、 cat
コマンドラインプログラムの機能を使用して、ファイルの内容を読み取り、を使用して端末に出力します。 createReadStream
関数。 次のステップでは、を使用して端末からの入力に基づいてファイルを作成します createWriteStream()
.
ステップ3—ファイルへの書き込み createWriteStream()
このセクションでは、を使用して端末からファイルに入力を書き込みます。 createWriteStream()
. The createWriteStream
関数は、データを書き込むことができる書き込み可能なファイルストリームを返します。 前のステップの読み取り可能なストリームと同様に、この書き込み可能なストリームは、次のような一連のイベントを発行します。 error
, finish
、 と pipe
. さらに、それは提供します write
チャンクまたはビットでストリームにデータを書き込むための関数。 The write
関数は、 chunk
、これは文字列である可能性があります Buffer
, <Uint8Array>
、またはその他のJavaScript値。 チャンクが文字列の場合は、エンコーディングタイプを指定することもできます。
端末からファイルに入力を書き込むには、次の関数を作成します。 write
コマンドラインプログラムで。 この関数では、端末から入力を受け取り(ユーザーが入力を終了するまで)、データをファイルに書き込むプロンプトを作成します。
まず、インポートする必要があります readline
上部のモジュール mycliprogram
ファイル。 The readline
moduleは、標準入力のような読み取り可能なストリームからデータを受信するために使用できるネイティブNode.jsモジュールです(stdin
)または端末を一度に1行ずつ。 あなたの mycliprogram
ファイルを作成し、強調表示された行を追加します。
#!/usr/bin/env node
const fs = require('fs');
const readline = require('readline');
次に、以下のコードを追加します read()
関数。
...
function write(filePath) {
const writableStream = fs.createWriteStream(filePath);
writableStream.on('error', (error) => {
console.log(`An error occured while writing to the file. Error: ${error.message}`);
});
}
ここでは、書き込み可能なストリームを作成しています filePath
パラメータ。 このファイルパスは、後のコマンドライン引数になります write
語。 また、何か問題が発生した場合(たとえば、 filePath
それは存在しません)。
次に、端末からメッセージを受信するためのプロンプトを作成し、指定されたメッセージに書き込みます filePath
を使用して readline
以前にインポートしたモジュール。 readlineインターフェース、プロンプトを作成し、 line
イベント、更新 write
ブロックに示されているように機能します。
...
function write(filePath) {
const writableStream = fs.createWriteStream(filePath);
writableStream.on('error', (error) => {
console.log(`An error occured while writing to the file. Error: ${error.message}`);
});
const rl = readline.createInterface({
input: process.stdin,
output: process.stdout,
prompt: 'Enter a sentence: '
});
rl.prompt();
rl.on('line', (line) => {
switch (line.trim()) {
case 'exit':
rl.close();
break;
default:
sentence = line + '\n'
writableStream.write(sentence);
rl.prompt();
break;
}
}).on('close', () => {
writableStream.end();
writableStream.on('finish', () => {
console.log(`All your sentences have been written to ${filePath}`);
})
setTimeout(() => {
process.exit(0);
}, 100);
});
}
readlineインターフェースを作成しました(rl
)プログラムが標準入力を読み取ることができるようにします(stdin
)端末から行ごとに、指定されたものを書き込みます prompt
標準出力への文字列(stdout
). あなたはまた、 prompt()
構成されたものを書き込む関数 prompt
新しい行へのメッセージと、ユーザーが追加の入力を提供できるようにします。
次に、2つのイベントリスナーをチェーンしました。 rl
インターフェース。 最初のものは line
入力ストリームが行末入力を受信するたびに発行されるイベント。 この入力は改行文字(\n
)、キャリッジリターン文字(\r
)、または両方の文字を一緒に(\r\n
)、通常はを押すと発生します ENTER
または戻る ↵
コンピューターのキー。 したがって、ターミナルに入力しているときにこれらのキーのいずれかを押すと、 line
イベントが発行されます。 コールバック関数は、1行の入力を含む文字列を受け取ります line
.
行をトリミングして、それが単語かどうかを確認しました exit
. そうでない場合、プログラムは改行文字をに追加します line
と書く sentence
に filePath
を使用して .write()
関数。 次に、プロンプト関数を呼び出して、ユーザーに別のテキスト行を入力するように促しました。 の場合 line
は exit
、プログラムは close
上の機能 rl
インターフェース。 The close
関数はを閉じます rl
インスタンスを作成し、標準入力を解放します(stdin
)および出力(stdout
)ストリーム。
この関数は、あなたが聞いた2番目のイベントに私たちを連れて行きます rl
インスタンス: close
イベント。 このイベントは、電話をかけると発生します rl.close()
. ストリームにデータを書き込んだ後、 end
ストリーム上で機能して、書き込み可能なストリームにデータを書き込まないようにプログラムに通知します。 これを行うと、データが出力ファイルに完全にフラッシュされます。 したがって、単語を入力すると exit
、あなたは閉じます rl
インスタンスを作成し、を呼び出して書き込み可能なストリームを停止します end
関数。
プログラムが端末から指定されたものにすべてのテキストを正常に書き込んだことをユーザーにフィードバックするため filePath
、あなたは聞いた finish
のイベント writableStream
. コールバック関数では、書き込みが完了したときにユーザーに通知するメッセージを端末に記録しました。 最後に、100ミリ秒後にプロセスを終了して、 finish
フィードバックを提供するイベント。
最後に、この関数をで呼び出すには mycliprogram
、交換してください console.log
のステートメント case 1
のブロック switch
新しいステートメント write
ここに示すように、関数:
...
switch (command){
...
case 1:
write(args[3]);
break;
...
}
新しい変更を含むファイルを保存します。 次に、ターミナルでコマンドラインアプリケーションを実行します。 write
指図。
- ./mycliprogram write output.txt
で Enter a sentence
プロンプトが表示されたら、必要な入力を追加します。 いくつかのエントリの後、次のように入力します exit
.
出力は次のようになります(強調表示された行の代わりに入力が表示されます)。
OutputEnter a sentence: Twinkle, twinkle, little star
Enter a sentence: How I wonder what you are
Enter a sentence: Up above the hills so high
Enter a sentence: Like a diamond in the sky
Enter a sentence: exit
All your sentences have been written to output.txt
小切手 output.txt
を使用してファイルの内容を表示するには read
以前に作成したコマンド。
- ./mycliprogram read output.txt
ターミナル出力には、コマンドに入力したすべてのテキストが含まれている必要があります。 exit
. 上記の入力に基づいて、 output.txt
ファイルには次の内容が含まれています。
OutputTwinkle, twinkle, little star
How I wonder what you are
Up above the hills so high
Like a diamond in the sky
このステップでは、ストリームを使用してファイルに書き込みました。 次に、コマンドラインプログラムでファイルをコピーする関数を実装します。
ステップ4—を使用してファイルをコピーする pipe()
このステップでは、 pipe
ストリームを使用してファイルのコピーを作成する関数。 ストリームを使用してファイルをコピーする方法は他にもありますが、 pipe
データフローを管理する必要がないため、これが推奨されます。
たとえば、ストリームを使用してファイルをコピーする1つの方法は、ファイルの読み取り可能なストリームを作成し、でストリームをリッスンすることです。 data
イベント、そしてそれぞれを書く chunk
ストリームイベントからファイルコピーの書き込み可能なストリームへ。 以下のスニペットは例を示しています。
const fs = require('fs');
const readableStream = fs.createReadStream('lorem-ipsum.txt', 'utf8');
const writableStream = fs.createWriteStream('lorem-ipsum-copy.txt');
readableStream.on('data', () => {
writableStream.write(chunk);
});
writableStream.end();
この方法の欠点は、読み取り可能ストリームと書き込み可能ストリームの両方でイベントを管理する必要があることです。
ストリームを使用してファイルをコピーするための推奨される方法は、 pipe
. 配管パイプは、水タンク(出力)などの水源から蛇口または蛇口(入力)に水を渡します。 同様に、 pipe
データを出力ストリームから入力ストリームに転送します。 (Linuxベースのbashシェルに精通している場合は、パイプ |
コマンドは、あるストリームから別のストリームにデータを転送します。)
Node.jsのパイピングは、最初の方法を使用する場合のようにデータフローを管理することなく、ソースからデータを読み取り、別の場所に書き込む機能を提供します。 前のアプローチとは異なり、読み取り可能ストリームと書き込み可能ストリームの両方でイベントを管理する必要はありません。 このため、ストリームを使用するコマンドラインアプリケーションにコピーコマンドを実装するための推奨されるアプローチです。
の中に mycliprogram
ファイルの場合、ユーザーがプログラムを実行したときに呼び出される新しい関数を追加します。 copy
コマンドライン引数。 コピー方法は pipe()
入力ファイルからファイルの宛先コピーにコピーします。 を作成します copy
後の機能 write
以下に示すように機能します。
...
function copy(filePath) {
const inputStream = fs.createReadStream(filePath)
const fileCopyPath = filePath.split('.')[0] + '-copy.' + filePath.split('.')[1]
const outputStream = fs.createWriteStream(fileCopyPath)
inputStream.pipe(outputStream)
outputStream.on('finish', () => {
console.log(`You have successfully created a ${filePath} copy. The new file name is ${fileCopyPath}.`);
})
}
コピー機能では、を使用して入力または読み取り可能なストリームを作成しました fs.createReadStream()
. また、宛先の新しい名前を生成し、ファイルのコピーを出力し、を使用して出力または書き込み可能なストリームを作成しました fs.createWriteStream()
. 次に、からデータをパイプしました inputStream
に outputStream
を使用して .pipe()
. 最後に、あなたは finish
イベントが発生し、ファイルのコピーが成功するとメッセージが出力されます。
書き込み可能なストリームを閉じるには、 end()
ストリームで機能します。 配管の場合、 end()
関数は書き込み可能なストリームで呼び出されます(outputStream
)読み取り可能なストリーム(inputStream
)を放出します end
イベント。 The end()
書き込み可能なストリームの機能は、 finish
イベントを実行し、このイベントをリッスンして、ファイルのコピーが終了したことを示します。
この機能の動作を確認するには、 mycliprogram
ファイルを更新し、 case 2
のブロック switch
以下に示すようなステートメント:
...
switch (command){
...
case 2:
copy(args[3]);
break;
...
}
を呼び出す copy
の機能 case 2
のブロック switch
ステートメントは、実行時に mycliprogram
とのプログラム copy
コマンドと必要なファイルパス、 copy
関数が実行されます。
走る mycliprogram
:
- ./mycliprogram copy lorem-ipsum.txt
出力は次のようになります。
OutputYou have successfully created a lorem-ipsum-copy.txt copy. The new file name is lorem-ipsum-copy.txt.
以内 node-file-streams
フォルダには、新しく追加された名前のファイルが表示されます lorem-ipsum-copy.txt
.
を使用して、コマンドラインプログラムにコピー機能を正常に追加しました。 pipe
. 次のステップでは、ストリームを使用してファイルのコンテンツを変更します。
ステップ5—を使用してファイルのコンテンツを元に戻す Transform()
このチュートリアルの前の3つのステップでは、ストリームを使用して作業しました。 fs
モジュール。 このセクションでは、を使用してファイルストリームを変更します Transform()
ネイティブからのクラス stream
モジュール。変換ストリームを提供します。 変換ストリームを使用して、データの読み取り、データの操作、および出力としての新しいデータの提供を行うことができます。 したがって、出力は入力データの「変換」です。 変換ストリームを使用するNode.jsモジュールには、 crypto
暗号化と zlib
モジュール付き gzip
ファイルの圧縮および解凍用。
を使用してカスタム変換ストリームを実装します Transform()
抽象クラス。 作成する変換ストリームは、ファイルの内容を1行ずつ反転します。これは、変換ストリームを使用してファイルの内容を必要に応じて変更する方法を示しています。
の中に mycliprogram
ファイル、追加します reverse
ユーザーがパスしたときにプログラムが呼び出す関数 reverse
コマンドライン引数。
まず、インポートする必要があります Transform()
他のインポートの下のファイルの上部にあるクラス。 以下に示すように、強調表示された行を追加します。
#!/usr/bin/env node
...
const stream = require('stream');
const Transform = stream.Transform || require('readable-stream').Transform;
以前のNode.jsバージョンでは v0.10
、 Transform
抽象クラスがありません。 したがって、上記のコードブロックには readable-streams
このプログラムが以前のバージョンのNode.jsで動作できるようにpolyfill。 Node.jsのバージョンが > 0.10
プログラムは抽象クラスを使用し、そうでない場合はポリフィルを使用します。
注:Node.jsバージョンを使用している場合 < 0.10
、実行する必要があります npm init -y
を作成するには package.json
ファイルを作成し、を使用してポリフィルをインストールします npm install readable-stream
ポリフィルを適用するための作業ディレクトリに移動します。
次に、を作成します reverse
あなたのすぐ下で機能する copy
関数。 その関数では、を使用して読み取り可能なストリームを作成します filePath
パラメータを指定して、反転ファイルの名前を生成し、その名前を使用して書き込み可能なストリームを作成します。 次に、作成します reverseStream
、のインスタンス Transform()
クラス。 あなたが電話するとき Transform()
クラスでは、1つの関数を含むオブジェクトを渡します。 この重要な機能は transform
関数。
下に copy
関数、以下のコードブロックを追加して、 reverse
関数。
...
function reverse(filePath) {
const readStream = fs.createReadStream(filePath);
const reversedDataFilePath = filePath.split('.')[0] + '-reversed.'+ filePath.split('.')[1];
const writeStream = fs.createWriteStream(reversedDataFilePath);
const reverseStream = new Transform({
transform (data, encoding, callback) {
const reversedData = data.toString().split("").reverse().join("");
this.push(reversedData);
callback();
}
});
readStream.pipe(reverseStream).pipe(writeStream).on('finish', () => {
console.log(`Finished reversing the contents of ${filePath} and saving the output to ${reversedDataFilePath}.`);
});
}
The transform
関数は3つのパラメーターを受け取ります。 data
, encoding
タイプ、および callback
関数。 この関数内で、データを文字列に変換し、文字列を分割し、結果の配列の内容を逆にして、それらを結合し直しました。 このプロセスは、データを順方向ではなく逆方向に書き換えます。
次に、接続しました readStream
に reverseStream
そして最後に writeStream
2つを使用して pipe()
機能。 最後に、あなたは finish
ファイルの内容が完全に取り消されたときにユーザーに警告するイベント。
上記のコードは、リッスンするために別の構文を使用していることに気付くでしょう。 finish
イベント。 聞く代わりに finish
のイベント writeStream
新しい行で、あなたは連鎖しました on
2番目に機能 pipe
関数。 一部のイベントリスナーをストリームにチェーンできます。 この場合、これを行うと、 on('finish')
上の機能 writeStream
.
まとめるには、 console.log
のステートメント case 3
のブロック switch
とのステートメント reverse()
.
...
switch (command){
...
case 3:
reverse(args[3]);
break;
...
}
この機能をテストするには、国の名前をアルファベット順に含む別のファイル( countrys.csv )を使用します。 以下のコマンドを実行して、作業ディレクトリにダウンロードできます。
- wget https://raw.githubusercontent.com/do-community/node-file-streams/999e66a11cd04bc59843a9c129da759c1c515faf/countries.csv
その後、実行できます mycliprogram
.
- ./mycliprogram reverse countries.csv
出力は次のようになります。
OutputFinished reversing the contents of countries.csv and saving the output to countries-reversed.csv.
の内容を比較する countries-reversed.csv
と countries.csv
変容を見るために。 それぞれの名前が逆に書かれ、名前の順序も逆になっています(「アフガニスタン」は「natsinahgfA」と書かれて最後に表示され、「ジンバブエ」は「ewbabmiZ」と書かれて最初に表示されます)。
これで、カスタム変換ストリームが正常に作成されました。 また、ファイル処理にストリームを使用する関数を使用してコマンドラインプログラムを作成しました。
結論
ストリームは、ネイティブNode.jsモジュールおよびさまざまな場所で使用されます yarn
と npm
データを処理する効率的な方法を提供するため、入出力操作を実行するパッケージ。 この記事では、さまざまなストリームベースの関数を使用してNode.jsのファイルを操作しました。 次のコマンドラインプログラムを作成しました read
, write
, copy
、 と reverse
コマンド。 次に、これらの各コマンドを、それに応じて名前が付けられた関数に実装しました。 関数を実装するには、次のような関数を使用しました createReadStream
, createWriteStream
, pipe
から fs
モジュール、 createInterface
からの機能 readline
モジュール、そして最後に要約 Transform()
クラス。 最後に、これらの関数を小さなコマンドラインプログラムにまとめました。
次のステップとして、作成したコマンドラインプログラムを拡張して、ローカルで使用する可能性のある他のファイルシステム機能を含めることができます。 良い例は、データを変換するためのパーソナルツールを作成することです。 .tsv
ソースをストリームして .csv
または複製しようとしています wget
この記事でGitHubからファイルをダウンロードするために使用したコマンド。
作成したコマンドラインプログラムは、コマンドライン引数自体を処理し、単純なプロンプトを使用してユーザー入力を取得します。 Node.jsスクリプトでコマンドライン引数を処理する方法およびInquirer.jsを使用してインタラクティブなコマンドラインプロンプトを作成する方法を参照すると、より堅牢で保守しやすいコマンドラインアプリケーションの構築について詳しく知ることができます。 。
さらに、Node.jsは、ユースケースに必要となる可能性のあるさまざまな Node.jsストリームモジュールクラス、メソッド、およびイベントに関する広範なドキュメントを提供します。