0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

C# Streamとは

Last updated at Posted at 2025-02-25

はじめに

C#のStreamクラスがなんのことかさっぱりわからなかったので纏める。
なぜStream継承クラス(FileStream/MemoryStream...)でデータを管理する必要があるのか?変数でいいのでは?と思った。さらにStreamと書いてあると、抽象的でよくわからない…。

ストリームとは

プログラミングの分野では、データの入出力全般を扱う抽象的なオブジェクトやデータ型を意味する場合が多い。データが出入りする何らかの対象(メモリ領域やファイル、ネットワークなど)をプログラム中で扱えるように抽象化したもので、接続や切断、書き込みや読み込みなどを簡易な操作で行うことができる。

FileStreamクラス

FileStream.Read()で読み込まれるbyte[]はファイルのエンコーディング方式に従ってバイナリデータに変換される。ファイルがUTF-8で保存されていれば、UTF-8でエンコードされる。

MemoryStreamクラス

MemoryStreamを使って、バイト配列を読み込んだ時。

MemoryStream も、ある byte[] のサイズ(配列の長さ)とカーソル位置が保持されます。
そして、例えばある byte[] の80バイト目から60バイト分読み出したい、といった場合に、カーソル位置を80バイト目に移動させ、そこから60バイト分読み出すことができます。
これは、次のように書くことができます。

var array = new byte[300];

// --- ここに本来はデータの操作が入る --- //

// array を元に MemoryStream を作成
var stream = new MemoryStream(array);

// 80バイト目から60バイト読み出す
var puts = new byte[60];
stream.Position = 80;
stream.Read(puts, 0, 60);

使用せずに読み込んだ時。MemoryStream使う意味あるの?

なお、以下の配列へのアクセスをするコードで、同様の puts を得られます。

var array = new byte[300];

// --- ここに本来はデータの操作が入る --- //

// 80バイト目から60バイト読み出す
var puts = new byte[60];
for (int i = 0; i < 60; i++)
   puts[i] = array[80 + i];

え、じゃあ何に使うん 。

使う意味あるらしい。

このプロダクトは文字列や数値としては扱えないデータが山ほどあり(画像や音声、もしかしたら地球外生命体のDNAの解析結果かもしれない)、それらはすべて byte[] で表すことになっています。だから、それら全てのアクセスを、 MemoryStream に置き換えなければなりません。たった1要素の読み込みでさえ、長ったらしく2,3行を書き連ねなければならないのです。

実際にそんなことがあるはずはありません。安心してください。 ところで次の例を見てくれ、こいつをどう思う?

// AESで暗号化するためのオブジェクトを初期化
var aes = new AesManaged();
aes.GenerateIV();
aes.GenerateKey();

// MemoryStreamを作成
var memStream = new MemoryStream();

// CryptoStreamを作成
var cryStream = new CryptoStream(memStream, aes.CreateEncryptor, >CryptoStreamMode.Write);

// CryptoStreamに書き込み
cryStream.Write(new byte[] { 1, 2, 3, 4, 5 }, 0, 5);

// MemoryStreamから読み出し
var read = byte[3];
memStream.Position = 1;
memStream.Read(read, 0, 3);

ちょっと難解ですが、 ある MemoryStream を参照する CryptoStream にデータを書き込むと、 MemoryStream に暗号化されたデータが書き込まれる コードです。

上記の例では read に暗号化されたデータの一部が代入されることになります。

さてこれをちょっとだけ改変しましょう。

// AESで暗号化するためのオブジェクトを初期化
var aes = new AesManaged();
aes.GenerateIV();
aes.GenerateKey();

// FileStreamを作成
var filStream = new FileStream("C:/hoge.enc", FileMode.Create);

// CryptoStreamを作成
var cryStream = new CryptoStream(filStream , aes.CreateEncryptor, CryptoStreamMode.Write);

// CryptoStreamに書き込み
cryStream.Write(new byte[] { 1, 2, 3, 4, 5 }, 0, 5);

だいたい想像がつくと思いますが、これは ある FileStream を参照する CryptoStream にデータを書き込むと、 FileStream に暗号化されたデータが書き込まれる(暗号化されたデータがファイルに書き込まれる) コードです。

驚くべきことに、このコードを先ほどのコードと比べると、 MemoryStream を FileStream にすり替えただけなのです。

つまり、 MemoryStream は、 byte[] を FileStream 、すなわち 変数操作とファイル操作と同等に扱えるようにするクラス ということなのです。
C# では、とくにデータの変換系の処理を Stream で行うような風潮があるように見えます。

バイト配列に読み出す。モックや一時的なバッファとして使われることが多い。

結論

文字列や数値(変数)では扱えない巨大なデータ(画像や音声等)をbyte配列を持ったストリームで管理するためのクラスと思われる。
(2025/2/17追記)基本的にはStreamにすべて読み出すのではなく、必要な時に必要なデータだけ読みこみ、メモリを節約する。Streamの本質的な強みは、逐次処理(シーケンシャルな読み書き)を可能にすることと、ほかのストリームと組み合わせてデータ変換を行うことにある。

Stream と IEnumerable / IAsyncEnumerable の類似性

Streamでは必要な時に必要なデータを読み込む使い方が一般的。
IEnumerable / IAsyncEnumerableも同じことが可能。

① 例:List での逐次処理
ListはIEnumerableを実装しているため、foreachを使って1 つずつ処理できる。

List<string> names = new List<string> { "Alice", "Bob", "Charlie" };

foreach (var name in names)
{
    Console.WriteLine(name);  // "Alice" → "Bob" → "Charlie" の順に処理
}

この場合、namesに含まれる各要素(string 型のオブジェクト)を1つずつ逐次的に処理している。
ただし、Listの場合はすべてのデータがメモリ上にあるため、データを遅延取得するわけではないことに注意すること。

② IEnumerable による遅延評価の逐次処理
IEnumerableはデータをすべてメモリに保持しなくても、逐次的に1つずつ処理することができる仕組みを持っている。

例えば、yield returnを使うと、リスト全体をメモリに持たずに、1つずつデータを返すようになる。

IEnumerable<int> GenerateNumbers()
{
    for (int i = 1; i <= 5; i++)
    {
        yield return i;  // 1 つずつデータを返す
    }
}

foreach (var num in GenerateNumbers())
{
    Console.WriteLine(num);  // 1 → 2 → 3 → 4 → 5 の順に処理
}

この場合、リスト全体を作らずに、1つずつデータを生成しながら処理している。

0
0
4

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?