はなちるのマイノート

Unityをメインとした技術ブログ。自分らしくまったりやっていきたいと思いますー!

【C#】MemoryStreamを利用してメモリにデータを読み書きする

はじめに

今回はMemoryStreamというメモリにデータを読み書きできるクラスの使い方について書きたいと思います。

docs.microsoft.com

定義

MemoryStream クラス (System.IO) | Microsoft Docs

使い方

MemoryStreamStreamの派生クラスであり、バイトの読み取りと書き込みをサポートしています。
Stream クラス (System.IO) | Microsoft Docs

Streamを利用する場合は3 つの基本的な操作を覚えればひとまずOKだと思います。

  • 読み取り - ストリームからバイト配列などのデータ構造体にデータを転送します。
  • 書き込み - データ ソースからストリームにデータを転送します。
  • シーク - ストリーム内の現在位置を照会および変更します。

ファイルおよびストリーム入出力 - .NET | Microsoft Docs


MemoryStreamを利用するにあたって、サンプルコードとそれに対応する動きを記述した図を作りました。

private static void Main(string[] args)
{
    UnicodeEncoding unicodeEncoding = new UnicodeEncoding();
    byte[] text = unicodeEncoding.GetBytes("こんにちは");

    // 10 : バイト配列の長さ
    Console.WriteLine(text.Length);

    // 100バイト分のCapacityを持つインスタンス作成
    using (MemoryStream stream = new MemoryStream(100))
    {
        // 0 : streamの現在のPosition
        Console.WriteLine(stream.Position);

        // 100 : ストリームに割り当てられたバイト数
        Console.WriteLine(stream.Capacity);

        foreach (var writeByte in text)
        {
            // ストリームの現在Positionにバイトを書き込み、ストリームのPositionを1バイトだけ進める
            stream.WriteByte(writeByte);
        }

        // 10
        Console.WriteLine(stream.Position);

        // ストリームの先頭から0バイトの位置にストリームのPositionを移動
        // SeekOrigin.Bigin : ストリームの先頭を指定
        // SeekOrigin.Current : ストリーム内の現在位置を指定
        // SeekOrigin.End : ストリームの末尾を指定
        stream.Seek(0, SeekOrigin.Begin);

        // 0
        Console.WriteLine(stream.Position);

        var result = new byte[10];
        for (var i = 0; i < result.Length; i++)
        {
            // バイトを読み取り、ストリームのPositionを1バイトだけ進める
            result[i] = (byte)stream.ReadByte();
        }

        // 10
        Console.WriteLine(stream.Position);

        // こんにちは
        Console.WriteLine(unicodeEncoding.GetString(result));
    }
}
MemoryStreamの動作

またReadByteWriteByteのように1バイトずつではなく、ReadWriteを利用することで複数バイトの読み書きを行えます。

private static void Main(string[] args)
{
    UnicodeEncoding unicodeEncoding = new UnicodeEncoding();
    byte[] text = unicodeEncoding.GetBytes("こんにちは");

    // 100byte分のCapacityを持つインスタンス作成
    using (MemoryStream stream = new MemoryStream(100))
    {
        // textをストリームに書き込む
        // buffer : データの書き込み元となるバッファー
        // offset : buffer内のバイトオフセット
        // count : 書き込む最大バイト数
        stream.Write(buffer: text, offset: 0, count: text.Length);

        // ストリームの先頭から0バイトの位置にストリームのPositionを移動
        // SeekOrigin.Bigin : ストリームの先頭を指定
        // SeekOrigin.Current : ストリーム内の現在位置を指定
        // SeekOrigin.End : ストリームの末尾を指定
        stream.Seek(0, SeekOrigin.Begin);

        var result = new byte[10];

        // データをresultに書き込む
        // buffer : 読み取られた文字を書き込むバイト配列
        // offset : buffer内のバイトオフセット
        // count : 読み取る最大バイト数
        stream.Read(buffer: result, offset: 0, count: result.Length);

        // こんにちは
        Console.WriteLine(unicodeEncoding.GetString(result));
    }
}
public override int Read (byte[] buffer, int offset, int count);
public override void Write (byte[] buffer, int offset, int count);

オーバーロードはいくつかあるので詳細は公式ドキュメントを見てみてください。