Stream と StreamReader

いきなり C# の話.最近,C# を触らなければならない状況になったので少しずつメモしていきます.

ある言語をさわり始めるときに,取りあえず覚えておいた方が良いものの一つに I/O の扱い方がありますが,C# では Stream と StreamReader がこれに当たるようです(書きこみ (StreamWriter) の方は保留).そんな訳で,今回は各種 Stream,および StreamReader の役割に関するメモ.

Stream

多くのプログラム同様,C# も標準入出力やファイルなどからの(バイトシーケンスの)入出力を「ストリーム」と呼ばれる概念に抽象化して read や write の(インターフェースの)共通化を図っているようです.基底クラスは System.IO.Stream で,このクラスは各種派生クラスのインターフェースを定義しています(参考:Stream メソッド (System.IO) - MSDN).

System.IO.Stream クラスからは数多くのストリームクラスが派生しています(参考:Stream 階層 (System.IO) - MSDN).主な派生クラスに下記のようなものがあります.

  • System.IO.FileStream
  • System.IO.MemoryStream
  • System.Net.Sockets.NetworkStream

System.IO.FileStream は,その名の通りファイルの入出力を扱うためのクラスです.

System.IO.MemoryStream は,主に(?)下記のように配列をストリームのように扱う際に使用します.

// using System;
// using System.IO;

int size = 65536;
byte[] buffer = new byte[size];
// buffer に何らかのデータを格納する処理...

MemoryStream vs = new MemoryStream(buffer);
// 何らかの処理...

System.Net.Sockets.NetworkStream は,TCP 通信などのソケットを通したデータのやり取りを行う際に使用するストリームクラスです.

// using System;
// using System.IO;
// using System.Net;
// using System.Net.Sockets;

string host = "www.example.com";
Socket client = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
client.Connect(new IPEndPoint(Dns.Resolve(host).AddressList[0], 80));

// 第 2 引数を省略 or false に指定すると,NetworkStream から Close() を読んでも Socket を閉じない.
NetworkStream ss = new NetworkStream(mySocket, true);
// 何らかの処理...

StreamReader

各種 Stream クラスは,対象から n バイト読み込む (Read(), ReadByte()) と言った単純なインターフェースのみを提供します.しかし,実際に読み込む際には,テキストファイルのようにエンコードを意識する必要があったりするなど,もう少し賢い(?)入出力用のメソッドが欲しくなります.そう言った,それぞれの用途に合わせた入出力のためのインターフェースを提供してくれる Stream のラッパクラス*1が StreamReader になります.主な StreamReader クラスには,下記の 2 つが存在します.

  • System.IO.StreamReader
  • System.IO.BinaryReader

System.IO.StreamReader は,System.IO.TextReader からの派生クラスでテキストによる入力を補助します.具体的には,ストリームから 1 文字読み込む Read(), n 文字を読み込む ReadBlock(), 1 行分の文字列を読み込む ReadLine() が定義されています.StreamReader は,コンストラクタに Encoding を指定する事ができます.Encoding を指定した場合には,StreamRreader は Encode にしたがって文字列を読み込みます(System.Text.Encoding.Unicode (UTF-16) が指定された場合には,2 Byte ずつ読み込む等).尚,Encoding が省略された場合には UTF-8 としてテキストを読み込むそうです.

System.IO.BinaryReader は,バイナリデータなどの入力を補助します.System.IO.BinaryReader には,ReadInt16(), ReadInt32() などのメソッドが定義されてあり,それぞれストリームから 2, 4 Byte 分のデータを読み取って Int16, Int32 に変換した結果を返します.

*1:この認識で正しいのかどうか分かりませんが.