ストリーム は、データをすべて一度にメモリへ読み込むのではなく、チャンク単位で逐次的に 処理します。これにより、すべてをバッファリングするとメモリを使い果たしてしまうような大きなデータ(巨大なファイルやネットワーク転送)を扱ううえで不可欠になります。
ストリームが解決する問題
js
data = fs..();
(data);
fs.()
.(transform)
.(fs.());
ストリームを使えば、ファイルサイズに関係なくメモリ使用量は一定に保たれます。一度に 1 つのチャンクを扱うからです。
Readable → source you read FROM (fs.createReadStream, http request)
Writable → destination you write TO (fs.createWriteStream, http response)
Duplex → both readable & writable (TCP socket)
Transform → modify data as it passes through (zlib gzip, encryption)
import { createReadStream, createWriteStream } from "fs";
import { createGzip } from "zlib";
// read → compress → write, all streaming, low memory
createReadStream("file.txt")
.pipe(createGzip()) // Transform: compress on the fly
.pipe(createWriteStream("file.txt.gz"));
pipe は readable を writable へ(間に transform を挟んで)接続し、フローを自動的に管理します。ストリームを組み合わせる慣用的な方法です。
import { pipeline } from "stream/promises";
await pipeline(
createReadStream("in.txt"),
createGzip(),
createWriteStream("out.gz")
); // ✅ cleans up all streams on error/completion (pipe alone leaks on errors)
pipeline は連鎖した .pipe() よりも好まれます。エラーを伝播し、すべてのストリームを適切にクリーンアップするからです。
✓ HTTP request/response bodies (req and res ARE streams)
✓ File reading/writing, file uploads/downloads
✓ Compression (zlib), encryption (crypto)
✓ Database cursors, large query results
✓ Real-time data processing, video streaming
Small data that fits comfortably in memory → readFile/simple buffering is simpler.
Streams add complexity; use them for LARGE or continuous data.
ストリームは、大きなデータや連続的なデータを メモリ効率よく 扱うための Node を特徴づける機能です。大きなアップロードでクラッシュするアプリと、どんなサイズでも一定のメモリで処理できるアプリの違いを生みます。
4 つの種類、pipe/pipeline による合成(そしてなぜ pipeline がより安全なのか)、そして HTTP のリクエスト/レスポンス自体がストリームであることを理解することは、スケーラブルなファイル処理、データ処理、プロキシサービスを Node で構築するうえで不可欠です。