DOSEIの日記

技術メモ+日常ログ

ファイルとか文字列の読み書き

System.IO にあるいろいろなクラスのまとめ。

まず、扱う対象として 2 つの側面がある。

  • 読み書きの対象として、文字列 (string クラス) と、ファイルやメモリのようなストリームがある。ストリームは、 Stream 抽象クラスで抽象化されている。というわけで、各種クラスは、 string か Stream を取り扱う。
  • 扱う内容の対象として、バイナリデータテキストデータがある。 int や double などのプリミティブ型の内部バイナリ表現、テキストにはエンコーディングが関連している。こういうある程度高度な表現の読み書きを支援する Binary{Reader,Writer} クラスと、 Text{Reader,Writer} 抽象クラスを基底に持つクラスがある。

Stream

ファイルストリームを扱う基本的なクラスが、 FileStream : Stream である。メモリなら MemoryStream : Stream を使う。 Stream には、バイト列の基本的な入出力である Read と Write と、1 バイト単位で読み書きする ReadByte, WriteByte があり、またランダムアクセスするための Seek なども持っている。したがって、単純なバイナリデータの読み書きはこれでできる。
FileStream のコンストラクタではファイル名を指定する。 string 型だが、その文字列そのものを操作の対象にするのではないことに注意(いや、注意しなくてもわかるか)。

基本的なバイト列の取り扱いより高度なことを行う場合は、なんちゃら Reader/Writer を使う。
プリミティブのバイナリ表現を読み書きするなら BinaryReader/Writer で、事前に用意した Stream インスタンスをコンストラクタに指定する。
テキストファイルを読み書きするなら、Stream インスタンスエンコーディングを指定して StreamReader/Writer : TextReader/Writer を使う。なお、これらはファイル名を指定して、直接ストリームを扱うこともできる。 TextReader/Writer 抽象クラスは、ストリームまたは(後述の)文字列を対象として、エンコーディングに絡んだめんどくさい文字列処理を担当してくれる。

ファイルに関連する操作を集めた static クラス File には、 FileStream を作成するいろいろな状況に特化したメソッドが用意されている。(便利なのかどうかはよくわからない。)中には、 File.ReadAllXXX といった、 Stream を明示的に取り扱わなくてもいいものもある。

文字列

string の内容を対象のデータとして扱うクラスは、 StringReader/Writer : TextReader/Writer がある。ところで、 MSDN の StringReader/Writer の解説はあまりにもひどい。何も解説していない(w

これは、 C で言うところの sprintf/sscanf, C++ の stringstream である。(なお、本文とは関係ないが、 strstream は「廃止された」ものなので、使ってはいけません。)

StringReader のコンストラクタでは、処理する string を渡す。ファイル名ではないので注意(いや、注意しなくてもわかるか)。これは、 TextReader なので、使い方は StreamReader と同じである。

StringWriter のほうは若干異なり、 string ではなく、 StringBuilder を書き込みの対象とする。というのも、 .NET の String は、まるで値型のようにふるまう特殊なクラスで、その内容が変更されることはない(不変性 (Immutability) と呼ばれている)。内容が変更できる文字列のオブジェクトとして、 StringBuilder がある。これは、 C++ の string みたいなもん(なのか?)で、自動的に長さが変更される。おなじみ ToString() で string に変換できる。