web-dev-qa-db-ja.com

Java FileInputStreamを閉じる

さて、私は以下を行っています(変数名が変更されました):


FileInputStream fis = null;
try
{
    fis = new FileInputStream(file);

    ... process ...

}
catch (IOException e)
{
    ... handle error ...
}
finally
{
    if (fis != null)
        fis.close();
}

最近、私はFindBugsを使い始めました。これは、ストリームを適切に閉じていないことを示唆しています。 finally {}ブロックで実行できることがあるかどうかを確認することにしました。そうすれば、そうですね、close()がIOExceptionをスローする可能性があります。ここで人々は何をすることになっていますか? Javaライブラリはチェックされた例外を非常に多くスローします。

32
Matt H

Java 7以上の場合 try-with-resources を使用する必要があります:

try (InputStream in = new FileInputStream(file)) {
  // TODO: work
} catch (IOException e) {
  // TODO: handle error
}

Java 6以下)で立ち往生している場合...

このパターンは、nullをいじるのを避けます。

    try {
        InputStream in = new FileInputStream(file);
        try {
            // TODO: work
        } finally {
            in.close();
        }
    } catch (IOException e) {
        // TODO: error handling
    }

closeを効果的に処理する方法の詳細については、次のブログ投稿を参照してください: Java:ストリーム処理を混乱させない方法 。より多くのサンプルコードとより多くの深さがあり、catchブロックでのcloseのラッピングの落とし穴をカバーしています。

44
McDowell

ストリームを閉じようとするときにIOExceptionをスローするか、飲み込むかは、次のようなもので実行できます。

FileInputStream fis = null;
try
{
    fis = new FileInputStream(file);

    ... process ...


}
catch (IOException e)
{
    ... blah blah blah ...
}
finally
{
    try
    {
        if (fis != null)
            fis.close();
    }
    catch (IOException e)
    {
    }
}
26
Max Stewart

JDK7に追加された try-with-resources 機能を使用できます。この種のものに対処するために正確に作成されました

static String readFirstLineFromFile(String path) throws IOException {
  try (BufferedReader br = new BufferedReader(new FileReader(path))) {
    return br.readLine();
  }
}

文書は言う:

Try-with-resourcesステートメントは、ステートメントの終わりに各リソースが確実に閉じられるようにします。

10
Edwin Dalorzo

単純な静的ヘルパーメソッドを使用することもできます。

public static void closeQuietly(InputStream s) {
   if (null == s) {
      return;
   }
   try {
      s.close();
   } catch (IOException ioe) {
      //ignore exception
   }
}

そしてあなたのfinallyブロックからこれを使用してください。

4
squiddle

非常にマイナーなスタイルの提案を除いて、追加するものは何もありません。 自己文書化コードの標準的な例はこの場合に適用されます-close()でキャッチする必要がある無視されたIOExceptionに説明的な変数名を付けます。

したがって、スクイドルの答えは次のようになります。

public static void closeQuietly(InputStream s) {
   try {
      s.close();
   } catch (IOException ignored) {
   }
}
3
serg10

ほとんどの場合、IO例外をキャッチし、単純にtry-finallyを使用するほうがnotのほうが良いと思います。

final InputStream is = ... // (assuming some construction that can't return null)
try {
    // process is
    ...
} finally {
    is.close();
}

FileNotFoundExceptionを除いて、通常、IOExceptionを「回避」することはできません。あとは、エラーを報告するだけです。通常は、コールスタックでさらに処理するので、例外を伝播するほうがよいと思います。

IOExceptionはチェック例外であるため、このコード(およびそのクライアント)はthrows IOExceptionであることを宣言する必要があります。それはうるさすぎるかもしれません、またはあなたはIOを使うことの実装詳細を明らかにしたくないかもしれません。その場合、IOExceptionRuntimeExceptionまたは抽象的な例外タイプにラップする例外ハンドラーでブロック全体をラップできます。

詳細:上記のコードは、tryブロックのclose操作でfinallyが生成されるときに、IOExceptionブロックからの例外を飲み込むことを認識しています。これは大きな問題だとは思いません。通常、tryブロックからの例外は、IOExceptionが失敗する原因となるcloseと同じになります(つまり、IOが正常に機能することはまれですそして、クローズの時点で失敗します。これが問題である場合は、クローズを「沈黙」させることは、トラブルに値するかもしれません。

2
Bruno De Fraine

次の解決策は、クローズの前に起こり得る例外を隠さずにクローズが失敗した場合に、例外を正しくスローします。

try {
    InputStream in = new FileInputStream(file);
    try {
        // work
        in.close();
    } finally {
        Closeables.closeQuietly(in);
    }
} catch(IOException exc) {
    // kernel panic
}

これは、もう一度closeを呼び出す 効果がない であるため機能します。

これはguava Closeables に依存しますが、 squiddle で示されるように、必要に応じて独自のcloseQuietlyメソッドを記述できます( serg1 も参照)。

Closeはストリームに最終バイトを書き込む可能性があるため、一般的なケースでは、closeエラーを報告することが重要です。バッファリングのため。そのため、ユーザーは失敗したかどうかを知りたいか、おそらく何らかの方法で行動したいと考えています。確かに、これはFileInputStreamの特定のケースでは当てはまらないかもしれませんが、わかりません(ただし、すでに述べた理由から、とにかく発生した場合は、閉じるエラーを報告する方がよいと思います)。

上記のコードは、埋め込まれたtryブロックの構造のため、理解するのが少し難しいです。 IOExceptionをスローするメソッドとキャッチするメソッドの2つのメソッドを使用すると、より明確になると考えられます。少なくともそれが私が選ぶものです。

private void work() throws IOException {
    InputStream in = new FileInputStream(file);
    try {
        // work
        in.close();
    } finally {
        Closeables.closeQuietly(in);
    }
}

public void workAndDealWithException() {
    try {
        work();
    } catch(IOException exc) {
        // kernel panic
    }
}

http://illegalargumentexception.blogspot.com/2008/10/Java-how-not-to-make-mess-of-stream.html (McDowellによって参照)に基づいています。

1

うまくいけば、私たちはJavaでいつかクロージャを取得し、それから多くの冗長性を失うでしょう。

そのため、代わりにjavaIOのどこかにインポートできるヘルパーメソッドがあり、おそらく「Closable」インターフェースとブロックが必要になります。そのヘルパーメソッド内では、try {closable.close()} catch(IOException ex){// blah}が一度だけ定義され、その後、次のように記述できます。

 Inputstream s = ....;
 withClosable(s) {
    //your code here
 }
0
Lars Westergren