TextWriter系クラスで最後まで内容が反映されないというトラブルの対処法についてご紹介いたします。

TextWriter

TextWriterとは、Stream系クラス (FileStream / MemoryStream) などに対して、データの書き込みを行うために提供されるクラスです。
TextWriterの拡張クラスとして次のようなクラスが System.IO 名前空間で提供されております。

表1 代表的なTextWriter系クラスと概要

クラス名

概要

StreamWriter

文字を特定のエンコーディングでストリームに書き込むための TextWriter を実装しています。

BinaryWriter

プリミティブ型をバイナリでストリームに書き込みます。特定のエンコーディングの文字列の書き込みをサポートします。

出典: MSDN

これらのクラス全般で発生しうるトラブルのお話です。

バッファリング機能


イメージ 1
図1 TextWriterのバッファリング機能

標準的なTextWriter系クラスは、Streamへの書き込みのトランザクションで発生するオーバーヘッドの軽減のため、内部でのバッファリング機能が実装されております。
ある程度のデータがTextWriterのインスタンス内でバッファリングされたのち、Streamへ実際の書き込みが行われます。
TextWriter系クラスからStreamへ内部バッファの書き込みが行われる前にプログラムが終了してしまうなどすると、バッファされたデータは消失します。

CloseメソッドとFlushメソッド

TextWriter系クラスには、Stream系クラス同様「Close」メソッドが実装されております。このメソッドは、ターゲットになっているStreamをクローズするものでありますが、実はそれだけではありません。
TextWriterでCloseを実施する際、内部ではStreamをCloseする前に先程紹介したバッファをStreamへ書き込む処理もおこなっております。
プログラムやスレッドが終了する前にCloseまで実施されていれば、正しくバッファの反映処理まで実行されます。
またこのClose処理は、TextWriter.Dispose()でも実行されるため、usingセクションでTextWriterを使用するなどの方法でバッファを反映されることも可能です。

バッファの反映処理は、Closeメソッド内以外でも単独で提供さております。
それがFlushメソッドです。

つまり、CloseメソッドではFlushメソッドとStreamのCloseメソッドが実行されているということになります。

AutoFlushプロパティ

TextWriterには、AutoFlushプロパティが用意されております。
このプロパティはbool型の値を取り、デフォルトではfalseです。このプロパティにtrueを設定すると、Write系メソッドが実行される度にFlush処理が実行されるようになります。
もちろん、書き込み処理でのオーバーヘッドが大きいタイプでのStreamでは、パフォーマンスに大きな影響が出てしまいますが、、

まとめ

原則としてTextWriterは必ずスレッドまたはプログラム終了前にCloseしましょう。
Closeを行う前にStreamに対してすべての書き込みを反映させる必要がある場合は、FlushメソッドやAutoFlushプロパティを活用しましょう。