プログラミングをしていると必ず出会う InputStream, OutputStream, そして Reader, Writer。 「結局どれを使えばいいの?」「なんでこんなに面倒なループを書くの?」と疑問に思ったことはありませんか? その答えは、**「メモリを節約しながら、あらゆる場所へデータを流すため」**の知恵にあります。

1. ストリームは「土管」である

データのやり取りをするとき、一番シンプルなのは「データを全部メモリに乗せる」ことです。しかし、1GBの動画ファイルやAPKファイルをそのままメモリに乗せたら、アプリは即座にクラッシュします。

そこで登場するのが**ストリーム(流体)**という考え方です。

データを受け側と送り側の間に「土管(パイプ)」を通し、データを少しずつ流し込むのです。

2. なぜ「16KBのバッファ」が必要なのか?

Androidのパッケージインストールなどでよく見る、あの泥臭い while ループの正体は何でしょうか。

Java

byte[] buffer = new byte[16384]; // 16KBのバケツ
int n;
while ((n = is.read(buffer)) >= 0) {
    os.write(buffer, 0, n);
}

これは、**「巨大なプール(データ)の水を、小さなバケツ(メモリ)で汲んで、別の場所に運んでいる」**作業です。

3. 「Stream」と「Reader / Writer」の違い

ここで一つ混乱しがちなのが、Reader / Writer の存在です。これらは「文字」を扱うための道具です。

「画像を送りたいなら Stream」「日記を書きたいなら Writer」と使い分けるのが正解です。

4. 抽象化の魔法:相手が誰でも「書く」だけ

OutputStream は抽象クラス(契約)です。システムが提供してくれる OutputStream もあれば、ファイルに書き込むもの、ネットワークに送るものもあります。

特筆すべきは、**「書き込み側(あなたのアプリ)は、相手の正体を知らなくていい」**ということです。

「これが土管の入り口です。ここに write してください」

と言われれば、相手が物理ファイルだろうが、Androidのシステムプロセスだろうが、はるか彼方のサーバーだろうが、あなたのコードは全く同じ write ループで動きます。これこそがオブジェクト指向の「ポリモーフィズム」の威力です。

5. パイプを連結する(デコレータ・パターン)

ストリームの真骨頂は「連結」にあります。

こうすると、あなたはただデータを流し込むだけで、**「暗号化されて圧縮されたデータ」**が自動的に送り出されます。


まとめ:ストリームを制する者はデータを制す

一見無駄に見える「バケツリレー」のコードは、実は**「どんなに大きなデータでも、どんなに貧弱な環境でも、どんな送り先に対しても、安全かつ確実にデータを届ける」**ための、コンピュータ界の偉大な発明なのです。

次に OutputStream を見かけたときは、「あ、今はシステムの土管にバケツで水を流し込んでるんだな」と思い出してみてください。