ディスクがいっぱいになるときにStreamのCloseを強制できない
この文書はVisual Studio 2003(.NET 1.1 SP1)とVisual Studio 2005(.NET 2.0)をベースに記述されています 。
まず以下のソースを見てみてください。
SQL Serverのストアドプロシージャからは以下のような構文でreturnによる戻り値を返せます。
try { using ( System.IO.StreamWriter sw = new System.IO.StreamWriter(@"a:\gomi") ) { try { sw.Write(new char[16*1024*1024]); } finally { sw.Close(); } } } catch(System.IO.IOException er) { //ディスクフルなどのClose失敗などが考えられる。 }
一般的にファイルの書き出しを行うときに 、ディスクがいっぱいになった時やプログラムでエラーになることを考慮し、finallyでCloseと、usingを利用して破棄(Dispose)を強制させるつくりにするかと思います。
このCloseやDispose時に閉じることが出来なかった場合やFlushを行うことが出来なかった場合には例外が発生するために、さらにtryでくくる必要があります。
この例では何かあった場合には握りつぶしています。
このプログラムでディスクがいっぱいのドライブに書き出しを行って見ましょう。
ハンドルされていない例外 : System.IO.IOException: ディスクに十分な空き領域があり ません。 at System.IO.__Error.WinIOError(Int32 errorCode, String str) at System.IO.FileStream.WriteCore(Byte[] buffer, Int32 offset, Int32 count) at System.IO.FileStream.FlushWrite() at System.IO.FileStream.Flush() at System.IO.FileStream.Dispose(Boolean disposing) at System.IO.FileStream.Finalize()
このようにアプリケーションがクラッシュします、スタックトレースはコンソールアプリケーションなら出力されます。
このスタックトレースからわかることは、Writeで失敗して例外が出ています(1つ目のブロック)、その後finallyのCloseを実行しようとし内部でDisposeが呼ばれ、その内部でFlushが呼ばれています。(2つ目のブロック)、そして最終usingの処理としてDisposeが呼ばれます。(3つ目のブロック)
結局のところDisposeの中でFlushを呼んでいるせいで、強制Closeが出来ないためにハンドル出来ない状態になっています。
このClose出来ないためにアプリケーションがクラッシュするのが問題で、.NET1.1 SP1環境向けにはQFEというパッチが提供されています。
FIX: You receive exception error messages when you use the
StreamWriter.Flush () method or the StreamWriter.Close () method
to access a file on a disk that has insufficient space in .NET
Framework 1.1
http://support.microsoft.com/kb/892544/ja
これを適用した環境で上記の例外を握りつぶすコードを実行すると無事エラーが無く終了することが出来ます。
.NET1.1 SP2で対応されるといいのですが、お急ぎの方はQFEを入手してください。