クローズ処理で例外は発生するのか?

昔から疑問に思っているのだけど、ファイルやストリームでのclose処理ではどんな条件の時に例外(エラー)が発生するのだろうか?例えば、open処理ならファイルが存在しないと直ぐに例外が発生するし、write処理はディスク容量が無いとか書き込み権限がないと例外が発生する。read処理もネットワークでの読み込み時に接続が切れたりすると例外が発生しやすい。しかし、経験的に言ってclose処理ではなかなか例外が起こらないようだ。

例えば、JavaのInputStream#close()ではJavaDocに下記の説明が記載されている。仕様として「入出力エラー」が発生する可能性は確かに存在するらしい。

例外:
IOException - 入出力エラーが発生した場合

Oracle Technology Network for Java Developers | Oracle Technology Network | Oracle

例外が発生すると宣言されている以上、無視するわけには行かないので、当然のことながらfinally節でのclose処理は例外発生に対処した煩雑なものになってしまう。

    byte[] data = new byte[256];
    InputStream in = null;
    try {
        in = new FileInputStream("foo.txt");
        in.read(data);
    } catch (Exception ex) {
        ex.printStackTrace();
    } finally {
        try {
            if (in != null){
                in.close();
            }
        } catch (IOException ex) {
            ex.printStackTrace();
        } finally {
            ...
        }
    }

こんな冗長なコードを何度も書き連ねるのは煩雑なので、Apache CommonsにはcloseQuietly()なる便利なユーティリティが用意されている。これを使えば上記の最初のfinally節の中は1行だけの処理に置き換えられるわけだ。

Unconditionally close an InputStream.
Equivalent to InputStream.close(), except any exceptions will be ignored. This is typically used in finally blocks.

http://commons.apache.org/io/api-release/org/apache/commons/io/IOUtils.html#closeQuietly(java.io.InputStream)

ソースコードを見てみると、例外は見事に"ignore"されていることが分かる。

public static void closeQuietly(Reader input) {
    try {
        if (input != null) {
          input.close();
        }
    } catch (IOException ioe) {
        // ignore
    }
}

close()としては懸命に例外を投げようとしているはずだが、受け取る側は悉く無視してしまうようだ。実際問題として例外が起きても対処しようがないし、せいぜいログに出力する程度で終わってしまうのだろう。

同様の疑問に思うのは私だけではなかったようで(良かった!)、こんな質問も見かけた。やっぱりデバッガを使うとか特殊な状況を作り出さない限り、例外を発生させる確かな方法は無いようだ。

ソースには一切手を加えず、(5)ファイルのクローズでエラー表示させる方法はないでしょうか。

ファイルクローズ(fclose)でエラーを発生させる方法 【OKWAVE】

また、古い.NETではClose()時にFlushするものの、ディスク容量が足りない場合に失敗するという仕様(?)が有ったらしい。これが妥当な仕様として認められるかどうかは別として、問題発生の原因として筋は通っているおり、これはこれで納得出来る。ただ、他の要因が絡んでいるので、純粋にclose処理の問題とは言えないだろう。

本日、MicroSoftより正式に回答を頂きました。
回答は。。。。なんと仕様!!と言う事でした。(KBにないはずだ・・・)
以下はMicroSoftの回答(そのまま載せると問題なので要約)です。

                                                                                                                                  • -

[回答]
 ■NET Framework の動作仕様により発生している現象
 ■FileStream クラスや StreamWriter クラスは、Close を行う際に未書き込みのデータを Flush する処理を行っています。その際、ディスクに空き容量が無い場合には、Flush によるデータの書き込みを保証できないため、例外が発生いたします。

VB.NETで空き容量がない場合にFileCloseできない。: DOBON.NETプログラミング掲示板過去ログ

リソースの後片付け役として欠かせないclose処理だけど、そこで発生した問題に対する取り扱いについては、やや中途半端な印象が拭えないと思っている。