web-dev-qa-db-fra.com

Fermer un Java FileInputStream

D'accord, j'ai fait ce qui suit (les noms des variables ont été modifiés):


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

    ... process ...

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

Récemment, j'ai commencé à utiliser FindBugs, ce qui suggère que je ne ferme pas correctement les flux. Je décide de voir s'il y a quelque chose à faire avec un bloc finally {}, puis je vois, oh oui, close () peut lancer IOException. Que sont censés faire les gens ici? Les bibliothèques Java jettent trop d'exceptions vérifiées.

32
Matt H

Pour Java 7 et supérieur try-with-resources doit être utilisé:

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

Si vous êtes bloqué sur Java 6 ou inférieur ...

Ce modèle évite de contourner avec null :

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

Pour plus de détails sur la façon de gérer efficacement - fermer, lisez cet article de blog: Java: comment ne pas gâcher la gestion des flux . Il a plus d'exemples de code, plus de profondeur et couvre les pièges de l'encapsulage close dans un bloc catch.

44
McDowell

Quelque chose comme ce qui suit devrait le faire, à vous de décider si vous lancez ou avalez l'IOException en tentant de fermer le flux.

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

Vous pouvez utiliser la fonction try-with-resources ajoutée JDK7. Il a été créé précisément pour faire face à ce genre de choses

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

La documentation dit:

L'instruction try-with-resources garantit que chaque ressource est fermée à la fin de l'instruction.

10
Edwin Dalorzo

Vous pouvez également utiliser une méthode d'assistance statique simple:

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

et utilisez-le depuis votre bloc enfin.

4
squiddle

Rien à ajouter, à part une très petite suggestion stylistique. L'exemple canonique du code auto-documenté s'applique dans ce cas - donnez un nom de variable descriptive au IOException ignoré que vous devez attraper sur close().

Alors la réponse de squiddle devient:

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

Dans la plupart des cas, je trouve qu'il est juste préférable pas d'attraper les exceptions IO, et d'utiliser simplement try-finally:

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

À l'exception de FileNotFoundException, vous ne pouvez généralement pas "contourner" un IOException. La seule chose qui reste à faire est de signaler une erreur, et vous gérerez généralement cela plus haut dans la pile des appels, donc je trouve préférable de propager l'exception.

Puisque IOException est une exception vérifiée, vous devrez déclarer que ce code (et n'importe lequel de ses clients) throws IOException. Cela peut être trop bruyant ou vous ne voudrez peut-être pas révéler les détails de mise en œuvre de l'utilisation d'E/S. Dans ce cas, vous pouvez encapsuler le bloc entier avec un gestionnaire d'exceptions qui enveloppe le IOException dans un RuntimeException ou un type d'exception abstrait.

Détail: Je suis conscient que le code ci-dessus avale toute exception du bloc try lorsque l'opération close dans le bloc finally produit un IOException. Je ne pense pas que ce soit un gros problème: généralement, l'exception du bloc try sera la même IOException ce qui entraînera l'échec de close (c'est-à-dire qu'il est assez rare pour IO pour fonctionner correctement puis échouer au moment de la fermeture). Si cela est un problème, cela pourrait valoir la peine de "faire taire" la fermeture.

2
Bruno De Fraine

La solution suivante lève correctement une exception si la fermeture échoue sans masquer une exception possible avant la fermeture.

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

Cela fonctionne parce que l'appel à la fermeture une deuxième fois n'a aucun effet .

Cela repose sur la goyave Closeables , mais on peut écrire sa propre méthode closeQuietly si elle est préférée, comme indiqué par squiddle (voir aussi serg1 ).

Signaler une erreur de fermeture, dans le cas général, est important car close pourrait écrire certains octets finaux dans le flux, par exemple à cause de la mise en mémoire tampon. Par conséquent, votre utilisateur veut savoir s'il a échoué, ou vous voulez probablement agir d'une manière ou d'une autre. Certes, cela pourrait ne pas être vrai dans le cas spécifique d'un FileInputStream, je ne sais pas (mais pour les raisons déjà mentionnées, je pense qu'il est préférable de signaler une erreur de fermeture si elle se produit de toute façon).

Le code ci-dessus est un peu difficile à saisir en raison de la structure des blocs d'essai intégrés. Il peut être considéré comme plus clair avec deux méthodes, l'une qui lève une exception IOException et l'autre qui l'attrape. C'est du moins ce que j'opterais.

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
    }
}

Basé sur http://illegalargumentexception.blogspot.com/2008/10/Java-how-not-to-make-mess-of-stream.html (référencé par McDowell).

1
Olivier Cailloux

Espérons que nous obtiendrons des fermetures dans Java un jour, puis nous perdrons beaucoup de verbosité.

Donc, à la place, il y aura une méthode d'aide quelque part dans javaIO que vous pouvez importer, cela prendra probablement une interface "Closable" et aussi un bloc. A l'intérieur de cette méthode d'assistance, la tentative {closable.close ()} catch (IOException ex) {// blah} est définie une fois pour toutes, et vous pourrez alors écrire

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