2012-04-01 13 views
2

これを処理するより良い方法があるかどうかを知りたかっただけです。ストリームを理解している限り、ストリームを閉じる限り、そのストリーム内にカプセル化されたストリームはすべて閉じられるため、最終的にはTarArchiveOutputStreamを閉じるだけです。私がrawDirまたはarchiveDirでFileNotFoundを取得した場合はログに記録します。それ以外の場合はスローしたいものです。Java、例外の処理と終了、tryとfinallyのストリーム

public static void createTarGzOfDirectory(File rawDir, File archiveFile) throws IOException { 
    FileOutputStream fOut = null; 
    BufferedOutputStream bOut = null; 
    GzipCompressorOutputStream gzOut = null; 
    TarArchiveOutputStream tOut = null; 
    try { 
     fOut = new FileOutputStream(archiveFile); 
     bOut = new BufferedOutputStream(fOut); 
     gzOut = new GzipCompressorOutputStream(bOut); 
     tOut = new TarArchiveOutputStream(gzOut); 
     addFileToTarGz(tOut, rawDir, ""); 
    } catch (FileNotFoundException e) { 
     log.error("File not found: " + e); 
    } finally { 
     if(tOut != null) { 
      tOut.finish(); 
      tOut.close(); 
     } 
    } 

改善のためのその他の考慮事項や考え方はありますか?

+0

なぜあなたは「仕上げ」と呼ぶと思いますか? – bmargulies

答えて

3

ストリームの私の理解では、限り、あなたはストリームを閉じるように、その中にカプセル化された任意のストリームがクローズされるということです...

正しいです。

しかし、tOutnullの場合、チェーン内の他のストリームは作成されていません。それはやや厄介な前提です。

  1. FileOutputStreamが作成され、fOutに割り当てられています。
  2. BufferedOutputStreamが作成され、bOutに割り当てられます。
  3. GzipCompressorOutputStreamコンストラクタが例外またはエラーをスローします。 (たぶんヒープがいっぱいです...)。
  4. catchはスキップされています...間違った例外です。
  5. finallyチェックtOut、それはnullで見つけて、何もしません。

結果:FileOUtputStreamが保持するファイル記述子/チャネルがリークしました。

(絶対的に)右この例を取得するための鍵は、重要なリソースを保持し、そのストリームが閉じされることを保証すること、それらのストリームオブジェクトのかを理解することです。リソースを保持していない他のストリームは、閉じる必要はありません。

} finally { 
    if (fOut != null) { 
     fOut.close(); 
    } 
} 

他のポイントは、あなたがaddFileToTarGz呼び出しの後tryブロックにtOut.finish()コールを移動する必要があるということです。

  • addFileToTarGz呼び出しが例外をスローした場合、またはあなたがそこまで取得しない場合は、finishコールは時間の無駄です。

  • finishコールは、インデックスをアーカイブに書き込もうとしますが、IOExceptionをスローする可能性があります。これがfinallyブロックで発生した場合、ストリームチェーンを閉じるfinallyブロックの次のコードは実行されず、ファイル記述子がリークします。

+1

nullをチェックすると、理由がないために複雑さが増します。 'try'の前に宣言で' fOut'を初期化してください。 – erickson

+0

@erikson - 私はそれを認識しています。しかし、そうした場合、FileNotFound例外を報告するために別の囲みtry-catchが必要になります。私の答えは、問題の最も洗練された解決策ではなく、正解です。 –

+1

通常、このレベルで例外が処理されると、それらは正しく処理されません。メソッドは 'IOException'をスローするので、何かを' catch 'しないのが正しいでしょう。それは本当に "優雅さ"に関するものではありません。簡単なコードを正しいものにする方が簡単です。 – erickson

0

あなたは可能性が一緒にそうようなチェーンのすべてのあなたのコンストラクタを:

tOut = new TarArchiveOutputStream(new GzipCompressorOutputStream(new BufferedOutputStream(new FileOutputStream(archiveFile)))); 

そして自分自身に初期の6行とデバッグのための3つのローカル変数を保存します。他の人が自分のやり方を好むかもしれません。

ストリームを閉じるまでは、私には正しいように見えます。

+3

GzipCOmpressorOutpuStreamコンストラクタが例外をスローするとどうなりますか?どのように他のものを閉じるのですか? –

+0

@GuillaumePolet - 理論的にはリークです。実際には、例外が発生する原因を検討し、繰り返し発生する可能性があるかどうかを判断する必要があります。 –

+0

@StephenC合意。しかし、それが数回しか起こらなくても、私はあなたがそれらの事例を予見して、とにかくストリームを閉じるべきだと思います。中間コンストラクタで例外をスローすることができない場合は、もちろん時間の無駄です。 –

1

醜いかもしれませんが、多分そうではないかもしれませんが、それらをすべてカスケードで閉じるべきです。はい、TarArchiveOutputStreamを閉じると、下位のストリームを閉じることになっています。しかし、実装によっては、必ずしもそうであるとは限りません。さらに、おそらく主に、中間コンストラクタの1つが例外をスローすると、tOutはnullになりますが、他のコンストラクタはnullになる可能性があります。あなたのストリームは開かれているが、あなたのストリームは閉じられていないことを意味します。

関連する問題