開発者ドキュメント

Node.jsでストリームを使用してファイルを操作する方法

序章

コンピューティングにおけるストリームの概念は、通常、安定した連続的なフローでのデータの配信を表します。 ソースからの読み取りまたはソースへの書き込みにストリームを継続的に使用できるため、すべてのデータを一度にメモリに収める必要がなくなります。

ストリームを使用すると、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.createReadStreamfs.createWriteStream 機能。 また、あるストリームの出力を別のストリームの入力として使用し、カスタム変換スチームを実装します。 これらのアクションを実行することで、ストリームを使用してNode.jsのファイルを操作する方法を学びます。 これらの概念を示すために、コマンドラインプログラムを作成して、 cat Linuxベースのシステムに見られる機能、端末からファイルへの入力の書き込み、ファイルのコピー、およびファイルのコンテンツの変換。

前提条件

このチュートリアルを完了するには、次のものが必要です。

ステップ1—ファイル処理コマンドラインプログラムの設定

このステップでは、基本的なコマンドを使用してコマンドラインプログラムを作成します。 このコマンドラインプログラムは、チュートリアルの後半で学習する概念を示します。ここでは、ファイルを操作するために作成する関数でこれらのコマンドを使用します。

まず、このプログラムのすべてのファイルを含むフォルダーを作成します。 ターミナルで、という名前のフォルダを作成します node-file-streams:

  1. mkdir node-file-streams

を使用して cd コマンドを実行し、作業ディレクトリを新しいフォルダに変更します。

  1. cd node-file-streams

次に、というファイルを作成して開きます mycliprogram お気に入りのテキストエディタで。 このチュートリアルではGNUを使用します nano、ターミナルテキストエディタ。 nanoを使用してファイルを作成して開くには、次のコマンドを入力します。

  1. nano mycliprogram

テキストエディタで、次のコードを追加してshebangを指定し、Node.jsプロセスからのコマンドライン引数の配列を格納し、アプリケーションに必要なコマンドのリストを格納します。

node-file-streams / mycliprogram
#!/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 ファイル:

node-file-streams / 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 適切な応答を提供します。

node-file-streams / mycliprogram
...
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 配列。 アイテムが存在しない場合は、続行するにはファイルパスが必要であることを示すメッセージが端末に出力されます。

ファイルを保存します。 次に、アプリケーションを実行します。

  1. ./mycliprogram

あなたは得るかもしれません permission denied 以下の出力と同様のエラー:

Output
-bash: ./mycliprogram: Permission denied

このエラーを修正するには、ファイルに実行権限を付与する必要があります。これは、次のコマンドで実行できます。

  1. chmod +x mycliprogram

ファイルを再実行してください。 出力は次のようになります。

Output
simplecli 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 ファイルを作成し、以下のコードを追加します。

node-file-streams / 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 コマンドと任意のファイル名:

  1. ./mycliprogram read test.txt

出力は次のようになります。

Output
command 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でホストされます。 ターミナルで、次のコマンドを入力して、ファイルを作業ディレクトリにダウンロードします。

  1. wget https://raw.githubusercontent.com/do-community/node-file-streams/999e66a11cd04bc59843a9c129da759c1c515faf/lorem-ipsum.txt

複製するには cat コマンドラインアプリケーションの機能をインポートするには、 fs モジュールが含まれているため createReadStream 必要な機能。 これを行うには、 mycliprogram ファイルを作成し、シバンの直後にこの行を追加します。

node-file-streams / mycliprogram
#!/usr/bin/env node

const fs = require('fs');

次に、以下の関数を作成します switch と呼ばれるステートメント read() 単一のパラメータを使用:読み取りたいファイルのファイルパス。 この関数は、そのファイルから読み取り可能なストリームを作成し、 data そのストリームのイベント。

node-file-streams / mycliprogram
...
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 以下のコードブロックに示すように:

node-file-streams / mycliprogram
...
switch (command){
    case 0:
        read(args[3]);
        break;
    ...
}

ファイルを保存して新しい変更を保持し、プログラムを実行します。

  1. ./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.

node-file-streams / mycliprogram

...
const readableStream = fs.createReadStream(filePath, 'utf8')
...

プログラムを再実行すると、ターミナルにファイルの内容が表示されます。 プログラムは、からloremipsumテキストを出力します。 lorem-ipsum.txt ファイルに表示されるとおりに1行ずつファイルします。

Output
Lorem 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 ファイルを作成し、強調表示された行を追加します。

node-file-streams / mycliprogram
#!/usr/bin/env node

const fs = require('fs');
const readline = require('readline');

次に、以下のコードを追加します read() 関数。

node-file-streams / mycliprogram
...
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 ブロックに示されているように機能します。

node-file-streams / mycliprogram
...
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 と書く sentencefilePath を使用して .write() 関数。 次に、プロンプト関数を呼び出して、ユーザーに別のテキスト行を入力するように促しました。 の場合 lineexit、プログラムは 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 ここに示すように、関数:

node-file-streams / mycliprogram
...
switch (command){
    ...

    case 1:
        write(args[3]);
        break;

    ...
}

新しい変更を含むファイルを保存します。 次に、ターミナルでコマンドラインアプリケーションを実行します。 write 指図。

  1. ./mycliprogram write output.txt

Enter a sentence プロンプトが表示されたら、必要な入力を追加します。 いくつかのエントリの後、次のように入力します exit.

出力は次のようになります(強調表示された行の代わりに入力が表示されます)。

Output
Enter 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 以前に作成したコマンド。

  1. ./mycliprogram read output.txt

ターミナル出力には、コマンドに入力したすべてのテキストが含まれている必要があります。 exit. 上記の入力に基づいて、 output.txt ファイルには次の内容が含まれています。

Output
Twinkle, 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 ストリームイベントからファイルコピーの書き込み可能なストリームへ。 以下のスニペットは例を示しています。

example.js
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 以下に示すように機能します。

node-file-streams / mycliprogram
...
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(). 次に、からデータをパイプしました inputStreamoutputStream を使用して .pipe(). 最後に、あなたは finish イベントが発生し、ファイルのコピーが成功するとメッセージが出力されます。

書き込み可能なストリームを閉じるには、 end() ストリームで機能します。 配管の場合、 end() 関数は書き込み可能なストリームで呼び出されます(outputStream)読み取り可能なストリーム(inputStream)を放出します end イベント。 The end() 書き込み可能なストリームの機能は、 finish イベントを実行し、このイベントをリッスンして、ファイルのコピーが終了したことを示します。

この機能の動作を確認するには、 mycliprogram ファイルを更新し、 case 2 のブロック switch 以下に示すようなステートメント:

node-file-streams / mycliprogram
...
switch (command){
    ...

    case 2:
        copy(args[3]);
        break;
    
    ...
}

を呼び出す copy の機能 case 2 のブロック switch ステートメントは、実行時に mycliprogram とのプログラム copy コマンドと必要なファイルパス、 copy 関数が実行されます。

走る mycliprogram:

  1. ./mycliprogram copy lorem-ipsum.txt

出力は次のようになります。

Output
You 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() 他のインポートの下のファイルの上部にあるクラス。 以下に示すように、強調表示された行を追加します。

mycliprogram
#!/usr/bin/env node
...
const stream = require('stream');
const Transform = stream.Transform || require('readable-stream').Transform;

以前のNode.jsバージョンでは v0.10Transform 抽象クラスがありません。 したがって、上記のコードブロックには 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 関数。

node-file-streams / mycliprogram
...
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 関数。 この関数内で、データを文字列に変換し、文字列を分割し、結果の配列の内容を逆にして、それらを結合し直しました。 このプロセスは、データを順方向ではなく逆方向に書き換えます。

次に、接続しました readStreamreverseStream そして最後に writeStream 2つを使用して pipe() 機能。 最後に、あなたは finish ファイルの内容が完全に取り消されたときにユーザーに警告するイベント。

上記のコードは、リッスンするために別の構文を使用していることに気付くでしょう。 finish イベント。 聞く代わりに finish のイベント writeStream 新しい行で、あなたは連鎖しました on 2番目に機能 pipe 関数。 一部のイベントリスナーをストリームにチェーンできます。 この場合、これを行うと、 on('finish') 上の機能 writeStream.

まとめるには、 console.log のステートメント case 3 のブロック switch とのステートメント reverse().

node-file-streams / mycliprogram
...
switch (command){
    ...

    case 3:
        reverse(args[3]);
        break;
    
    ...
}

この機能をテストするには、国の名前をアルファベット順に含む別のファイル( countrys.csv )を使用します。 以下のコマンドを実行して、作業ディレクトリにダウンロードできます。

  1. wget https://raw.githubusercontent.com/do-community/node-file-streams/999e66a11cd04bc59843a9c129da759c1c515faf/countries.csv

その後、実行できます mycliprogram.

  1. ./mycliprogram reverse countries.csv

出力は次のようになります。

Output
Finished reversing the contents of countries.csv and saving the output to countries-reversed.csv.

の内容を比較する countries-reversed.csvcountries.csv 変容を見るために。 それぞれの名前が逆に書かれ、名前の順序も逆になっています(「アフガニスタン」は「natsinahgfA」と書かれて最後に表示され、「ジンバブエ」は「ewbabmiZ」と書かれて最初に表示されます)。

これで、カスタム変換ストリームが正常に作成されました。 また、ファイル処理にストリームを使用する関数を使用してコマンドラインプログラムを作成しました。

結論

ストリームは、ネイティブNode.jsモジュールおよびさまざまな場所で使用されます yarnnpm データを処理する効率的な方法を提供するため、入出力操作を実行するパッケージ。 この記事では、さまざまなストリームベースの関数を使用して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ストリームモジュールクラス、メソッド、およびイベントに関する広範なドキュメントを提供します。

モバイルバージョンを終了