web-dev-qa-db-fra.com

Est-il sûr d'utiliser Apache commons-io IOUtils.closeQuietly?

Est ce code

    BufferedWriter bw = new BufferedWriter(new FileWriter("test.txt"));
    try {
        bw.write("test");
    } finally {
        IOUtils.closeQuietly(bw);
    }

sûr ou pas? Autant que je sache, lorsque nous fermons un BufferedWriter, il videra son tampon dans le flux sous-jacent et peut échouer en raison d'une erreur. Mais l'API IOUtils.closeQuietly indique que toutes les exceptions seront ignorées.

Est-il possible qu'une perte de données passe inaperçue en raison de IOUtils.closeQuietly?

34
Evgeniy Dorofeev

Le code devrait ressembler à ceci en ce qui concerne le javadoc de closeQuietly():

BufferedWriter bw = null;

try {
    bw = new BufferedWriter(new FileWriter("test.txt"));
    bw.write("test");
    bw.flush(); // you can omit this if you don't care about errors while flushing
    bw.close(); // you can omit this if you don't care about errors while closing
} catch (IOException e) {
    // error handling (e.g. on flushing)
} finally {
    IOUtils.closeQuietly(bw);
}

closeQuietly() n'est pas destiné à un usage général au lieu d'appeler close() directement sur un Closable. Son cas d'utilisation est destiné à assurer la fermeture à l'intérieur d'un bloc finalement - toute la gestion des erreurs dont vous avez besoin doit être effectuée AVANT cela.

Cela signifie que si vous souhaitez réagir aux exceptions lors de l'appel de close() ou flush(), vous devez le gérer normalement. L'ajout de closeQuietly() dans votre bloc final assure simplement la fermeture, par ex. lorsque le rinçage a échoué et que la fermeture n'a pas été appelée dans try-block.

38
Fabian Barney

C'est sûr tant que votre application ne se soucie pas de savoir si l'écriture a réussi sans erreur. Si votre application doit gérer les erreurs d'écriture, cela n'est pas sûr car les données tamponnées vidées à la fermeture peuvent être perdues et l'erreur avalée.

7
McDowell

C'est possible en théorie mais je ne peux pas dire que j'aie jamais vu close () échouer. Généralement, l'échec rapide signifie qu'une précédente IO opérations telles que l'ouverture du fichier échouera en premier. Vous pouvez écrire une fermeture qui n'ignore pas les IOExceptions, mais cela pourrait écraser la véritable cause d'une exception si elle est quelque chose dans le bloc try/catch qui a échoué.

Ce que vous voulez, c'est quelque chose comme ce qui suit (ce qui est exagéré dans la plupart des cas)

try {
    // write to bw.
    bw.close(); // throw IOException if an error occurs.

} finally {
    // don't clobber a previous IOException
    IOUtils.closeQuietly(bw);
}
5
Peter Lawrey

Oui, il est sûr de l'utiliser, mais uniquement pour Java6 et inférieur. Depuis Java7 , vous devez utiliser try-with-resource .

Cela éliminera une grande partie du code standard que vous avez et la nécessité d'utiliser IOUtils.closeQuietly.

Maintenant, vous exemple:

    BufferedWriter bw = new BufferedWriter(new FileWriter("test.txt"));
    try {
        bw.write("test");
    } finally {
        IOUtils.closeQuietly(bw);
    }

Peut être écrit comme:

   try (BufferedWriter bw = new BufferedWriter(new FileWriter("test.txt"))) {
       bw.write("test");
   }

Il est important de noter que pour utiliser l'approche try-with-resource, votre ressource doit implémenter une nouvelle interface appelée Java.lang.AutoCloseable introduite dans Java 7.

De plus, vous pouvez inclure un certain nombre de ressources dans un bloc try-with-resource, il suffit de les séparer avec ;

   try (
       BufferedWriter bw1 = new BufferedWriter(new FileWriter("test1.txt"));
       BufferedWriter bw2 = new BufferedWriter(new FileWriter("test2.txt"))
   ) {
       // Do something useful with those 2 buffers!
   }   // bw1 and bw2 will be closed in any case
4
Johnny