.NET 小物置き場

byte 配列以外の配列に対応した MemoryStream

通常の MemoryStream は、データを読み書きするために byte 配列に変換しないといけませんが
これはちょっと不便なので、int と short を扱えるように継承してみました。
データはリトルエンディアンな並び方で挿入していきます。

文字列も一応 UTF-8 のものだけ実験的に入れれるようにしています。
文字列は、\n の有無で終端チェックをしているので、終端に \n の含まれない文字列(行)は書けますが、読み込めません。

・これから先の更新でやるべきこと
普通の MemoryStream より例外のチェック項目が少ないので、追加してインターフェイスを統一する
UTF-8 以外の文字列を扱えるようにする
ビッグエンディアンに対応する

自由にコピーして使ってください。
エラーチェックはそれなりにしていますが、
不十分だと思うので、ソースの検証をしてから使ってください。

…って後で気づいたんですが、同じことしようと思ったら、
BinaryReader っていうクラスがあるんですねw
残念ながら、これいらないと思います。

・図




ソースコード
//
// 更新日 2008/10/07
//

using System;
using System.Collections.Generic;
using System.IO;
using System.Text;

namespace Hikipuro.IO
{
    /// <summary>
    /// バッキング ストアとしてメモリを使用するストリームを作成します。
    /// <para>
    /// System.IO.MemoryStream の派生。
    /// バイト単位以外のサイズの読み書き可能。
    /// </para>
    /// </summary>
    class MemoryStreamM : MemoryStream
    {

        /// <summary>
        /// 現在のストリームからバイトのブロックを読み取り、データを buffer に書き込みます。
        /// </summary>
        /// <param name="buffer">このメソッドが戻るとき、指定した配列の offset から (offset + count - 1) までの値が、現在のストリームから読み取られた文字に置き換えられています。</param>
        /// <param name="offset">読み取りの開始位置を示す buffer 内の要素数 オフセット。</param>
        /// <param name="count">読み取る最大要素数。</param>
        public int Read(Int32[] buffer, int offset, int count)
        {
            int result = 0;
            int index = 0;

            if (buffer.Length < offset + count)
                throw new ArgumentException();

            while (index < count)
            {
                byte[] b = new byte[4] { 0, 0, 0, 0 };
                int bytes;

                bytes = this.Read(b, 0, 4);
                result += bytes;

                //Console.WriteLine("result[{0}] {1}", index, result);
                buffer[offset + index] = b[0];
                buffer[offset + index] |= (b[1] << 8);
                buffer[offset + index] |= (b[2] << 16);
                buffer[offset + index] |= (b[3] << 24);

                if (bytes < 4)
                    break;

                index++;
            }
            
            return result;
        }

        /// <summary>
        /// 現在のストリームからバイトのブロックを読み取り、データを buffer に書き込みます。
        /// </summary>
        /// <param name="buffer">このメソッドが戻るとき、指定した配列の offset から (offset + count - 1) までの値が、現在のストリームから読み取られた文字に置き換えられています。</param>
        /// <param name="offset">読み取りの開始位置を示す buffer 内の要素数 オフセット。</param>
        /// <param name="count">読み取る最大要素数。</param>
        public int Read(UInt32[] buffer, int offset, int count)
        {
            int result = 0;
            int index = 0;

            if (buffer.Length < offset + count)
                throw new ArgumentException();

            while (index < count)
            {
                byte[] b = new byte[4] { 0, 0, 0, 0 };
                int bytes;

                bytes = this.Read(b, 0, 4);
                result += bytes;

                //Console.WriteLine("result[{0}] {1}", index, result);
                buffer[offset + index] = b[0];
                buffer[offset + index] |= (UInt32)(b[1] << 8);
                buffer[offset + index] |= (UInt32)(b[2] << 16);
                buffer[offset + index] |= (UInt32)(b[3] << 24);

                if (bytes < 4)
                    break;

                index++;
            }

            return result;
        }

        /// <summary>
        /// 現在のストリームからバイトのブロックを読み取り、データを buffer に書き込みます。
        /// </summary>
        /// <param name="buffer">このメソッドが戻るとき、指定した配列の offset から (offset + count - 1) までの値が、現在のストリームから読み取られた文字に置き換えられています。</param>
        /// <param name="offset">読み取りの開始位置を示す buffer 内の要素数 オフセット。</param>
        /// <param name="count">読み取る最大要素数。</param>
        public int Read(Int16[] buffer, int offset, int count)
        {
            int result = 0;
            int index = 0;

            if (buffer.Length < offset + count)
                throw new ArgumentException();

            while (index < count)
            {
                byte[] b = new byte[2] { 0, 0 };
                int bytes;

                bytes = this.Read(b, 0, 2);
                result += bytes;

                //Console.WriteLine("result[{0}] {1}", index, result);
                buffer[offset + index] = b[0];
                buffer[offset + index] |= (Int16)(b[1] << 8);

                if (bytes < 4)
                    break;

                index++;
            }

            return result;
        }

        /// <summary>
        /// 現在のストリームからバイトのブロックを読み取り、データを buffer に書き込みます。
        /// </summary>
        /// <param name="buffer">このメソッドが戻るとき、指定した配列の offset から (offset + count - 1) までの値が、現在のストリームから読み取られた文字に置き換えられています。</param>
        /// <param name="offset">読み取りの開始位置を示す buffer 内の要素数 オフセット。</param>
        /// <param name="count">読み取る最大要素数。</param>
        public int Read(UInt16[] buffer, int offset, int count)
        {
            int result = 0;
            int index = 0;

            if (buffer.Length < offset + count)
                throw new ArgumentException();

            while (index < count)
            {
                byte[] b = new byte[2] { 0, 0 };
                int bytes;

                bytes = this.Read(b, 0, 2);
                result += bytes;

                //Console.WriteLine("result[{0}] {1}", index, result);
                buffer[offset + index] = b[0];
                buffer[offset + index] |= (UInt16)(b[1] << 8);

                if (bytes < 4)
                    break;

                index++;
            }

            return result;
        }

        /// <summary>
        /// 現在のストリームからバイトのブロックを読み取り、データを str に書き込みます。
        /// </summary>
        /// <param name="str">データの書き込み元となる文字列。</param>
        public int ReadLine(ref String str)
        {
            byte[] b = new byte[128];
            long start = 0;
            long end = 0;
            bool found = false;
            int bytes = 0;

            start = this.Position;
            end = start;

            while ((bytes = this.Read(b, 0, 128)) != 0)
            {
                for (int i = 0; i < bytes; i++)
                {
                    if (b[i] == '\n')
                    {
                        found = true;
                        end += i + 1;
                        break;
                    }
                }

                if (found == true)
                    break;

                end += 128;
            }

            if (found == false)
            {
                this.Seek(start, SeekOrigin.Begin);
                str = null;
                return 0;
            }

            b = new byte[end - start];
            this.Seek(start, SeekOrigin.Begin);
            this.Read(b, 0, b.Length);

            Encoding encode = Encoding.UTF8;
            str = encode.GetString(b).TrimEnd('\n', '\r');
            return (int)(end - start);
        }

        /// <summary>
        /// バッファから読み取ったデータを使用して、現在のストリームに Int32 のブロックを書き込みます。
        /// </summary>
        /// <param name="buffer">データの書き込み元となるバッファ。</param>
        /// <param name="offset">書き込むデータの開始位置を示す buffer 内の要素数 オフセット。</param>
        /// <param name="count">書き込む最大要素数。</param>
        public void Write(Int32[] buffer, int offset, int count)
        {
            int index = 0;

            if (buffer.Length < offset + count)
                throw new ArgumentException();

            while (index < count)
            {
                byte[] b = new byte[4] { 0, 0, 0, 0 };

                b[0] = (byte)((buffer[offset + index] >> 0) & 0xFF);
                b[1] = (byte)((buffer[offset + index] >> 8) & 0xFF);
                b[2] = (byte)((buffer[offset + index] >> 16) & 0xFF);
                b[3] = (byte)((buffer[offset + index] >> 24) & 0xFF);

                this.Write(b, 0, 4);
                index++;
            }
        }

        /// <summary>
        /// バッファから読み取ったデータを使用して、現在のストリームに UInt32 のブロックを書き込みます。
        /// </summary>
        /// <param name="buffer">データの書き込み元となるバッファ。</param>
        /// <param name="offset">書き込むデータの開始位置を示す buffer 内の要素数 オフセット。</param>
        /// <param name="count">書き込む最大要素数。</param>
        public void Write(UInt32[] buffer, int offset, int count)
        {
            int index = 0;

            if (buffer.Length < offset + count)
                throw new ArgumentException();

            while (index < count)
            {
                byte[] b = new byte[4] { 0, 0, 0, 0 };

                b[0] = (byte)((buffer[offset + index] >> 0) & 0xFF);
                b[1] = (byte)((buffer[offset + index] >> 8) & 0xFF);
                b[2] = (byte)((buffer[offset + index] >> 16) & 0xFF);
                b[3] = (byte)((buffer[offset + index] >> 24) & 0xFF);

                this.Write(b, 0, 4);
                index++;
            }
        }

        /// <summary>
        /// バッファから読み取ったデータを使用して、現在のストリームに Int16 のブロックを書き込みます。
        /// </summary>
        /// <param name="buffer">データの書き込み元となるバッファ。</param>
        /// <param name="offset">書き込むデータの開始位置を示す buffer 内の要素数 オフセット。</param>
        /// <param name="count">書き込む最大要素数。</param>
        public void Write(Int16[] buffer, int offset, int count)
        {
            int index = 0;

            if (buffer.Length < offset + count)
                throw new ArgumentException();

            while (index < count)
            {
                byte[] b = new byte[2] { 0, 0 };

                b[0] = (byte)((buffer[offset + index] >> 0) & 0xFF);
                b[1] = (byte)((buffer[offset + index] >> 8) & 0xFF);

                this.Write(b, 0, 2);
                index++;
            }
        }

        /// <summary>
        /// バッファから読み取ったデータを使用して、現在のストリームに UInt16 のブロックを書き込みます。
        /// </summary>
        /// <param name="buffer">データの書き込み元となるバッファ。</param>
        /// <param name="offset">書き込むデータの開始位置を示す buffer 内の要素数 オフセット。</param>
        /// <param name="count">書き込む最大要素数。</param>
        public void Write(UInt16[] buffer, int offset, int count)
        {
            int index = 0;

            if (buffer.Length < offset + count)
                throw new ArgumentException();

            while (index < count)
            {
                byte[] b = new byte[2] { 0, 0 };

                b[0] = (byte)((buffer[offset + index] >> 0) & 0xFF);
                b[1] = (byte)((buffer[offset + index] >> 8) & 0xFF);

                this.Write(b, 0, 2);
                index++;
            }
        }

        /// <summary>
        /// 文字列を使用して、現在のストリームに バイト配列 のブロックを書き込みます。
        /// </summary>
        /// <param name="str">データの書き込み元となる文字列。</param>
        public void Write(String str)
        {
            Encoding encode = Encoding.UTF8;
            byte[] b = encode.GetBytes(str);

            this.Write(b, 0, b.Length);
        }
    }
}