7
votes

Comment ferme un fichier après avoir attrapé une impression IoException en Java?

Tout,

J'essaie de vous assurer qu'un fichier que j'ai ouvert avec BuffereDreader est fermé lorsque j'attrape une impression IoException, mais il apparaît comme si mon objet BuffereReader est hors de portée dans le bloc de capture. P>

public static ArrayList readFiletoArrayList(String fileName, ArrayList fileArrayList)
{
    fileArrayList.removeAll(fileArrayList);

    try {
        //open the file for reading
        BufferedReader fileIn = new BufferedReader(new FileReader(fileName));

        // add line by line to array list, until end of file is reached
        // when buffered reader returns null (todo). 
        while(true){
                fileArrayList.add(fileIn.readLine());
            }
    }catch(IOException e){
        fileArrayList.removeAll(fileArrayList);
        fileIn.close(); 
        return fileArrayList; //returned empty. Dealt with in calling code. 
    }
}


0 commentaires

7 Réponses :


0
votes

Déplacez la déclaration du bloc d'essai:

if (fileIn != null)
    fileIn.close();


2 commentaires

S'il y a une exception dans les constructeurs de lecteurs (fichier non trouvé, par exemple), cela va exploser avec un NullPointException . Avoir à vérifier le null dans le attraper .


Dans votre capture, vous avez filein.close (); qui jette également une impression IoException. Le compilateur ne le permettra pas.



1
votes

Une fois que vous avez frappé le bloc de capture, toutes les variables déclarées dans l'essai ne sont plus scopées. Déclarer bufferedreader filein = null; Au-dessus du bloc d'essai, puis assignez-le à l'intérieur. Dans votre bloc de prise, faites si (filein! = Null) filein.close ();


0 commentaires

1
votes

Il se plaint du symbole ne pas être là parce que ce n'est pas le cas. C'est dans le bloc d'essai. Si vous souhaitez vous référer à FileDin, vous devrez le déclarer à l'extérieur de l'essai.

Cependant, il semble vraiment que vous voudriez que vous souhaitiez placer la fermeture d'un bloc enfin: vous devriez fermer le fichier indépendamment du succès ou défaillance avant de retourner. xxx


0 commentaires

24
votes
 BufferedReader fileIn = null;
 try {
       fileIn = new BufferedReader(new FileReader(filename));
       //etc.
 } catch(IOException e) {
      fileArrayList.removeall(fileArrayList);
 } finally {
     try {
       if (fileIn != null) fileIn.close();
     } catch (IOException io) {
        //log exception here
     }
 }
 return fileArrayList;
A few things about the above code:
close should be in a finally, otherwise it won't get closed when the code completes normally, or if some other exception is thrown besides IOException.
Typically you have a static utility method to close a resource like that so that it checks for null and catches any exceptions (which you never want to do anything about other than log in this context).
The return belongs after the try so that both the main-line code and the exception catching have a return method without redundancy.
If you put the return inside the finally, it would generate a compiler warning.

11 commentaires

+1 pour le enfin . Étonnamment, beaucoup de réponses n'ont pas mentionné à ce sujet. Voici quelques liaisons au soleil d'intérêt: Leçon: BASIC IO et Leçon: Exceptions


Vous pouvez supprimer la vérification de null et attraper exception , sauf si vous envisagez de dire à l'utilisateur que vous ne pouvez pas fermer le fichier et ne pouviez pas l'ouvrir. Mais, généralement, les utilisateurs ne s'en soucient pas.


Vous avez fermé la bufflededread, mais pas la filereader?


La fermeture de la buffereDreader fermera automatiquement la filereader.


@Bert: En effet, les classes Java IO suit le motif de décorateur. Donc, sous chaque fermer () déléguée vers le haut à l'instance décorée.


@Dave Jarvis, c'est certainement une alternative raisonnable, mais je pense que ce qui précède représente la meilleure pratique "standard". Mais tant que vous vous connectez l'exception, je pense que cela n'a pas vraiment d'importance.


Ce n'est pas considéré comme une meilleure pratique - plutôt ressource de ressources = acquérir (); essayez {user (ressource); } enfin {ressource.release (); } - Veuillez consulter ma réponse ci-dessous et liens là-bas


@MR_AND_MRS_D, le problème avec ce conseil est que l'acquisition est généralement la même exception que les opérations suivantes, ce qui entraîne la messmologie dans votre traitement des exceptions. Si vous considérez une exception sur la méthode de près d'équivalente aux autres exceptions, cela n'a pas d'importance, mais si vous souhaitez les gérer séparément, vous pouvez vérifier que NULL est la chose la plus propre à faire.


Vous voulez dire ressource ressource = acquérir (); essayez {user (ressource); } enfin {essayer {ressource.release (); } Catch {// Log et avalez}}} Comme je l'ai fait, causer généralement la ferme () L'exception n'est pas très importante (pas toujours - suivez les liens)


Est-ce juste moi, mais mettez un essai dans une prise pour la la même exception semble bizarrement redondante. Je comprends que nous devons le faire, mais il crie que quelque chose de fondamental est sérieusement imparfait.


C'est l'ancienne façon de faire des choses. La nouvelle fonctionnalité (Eh bien ... Java 7) pour fermer automatiquement les ressources doit être ajoutée d'abord dans cette réponse de manière préférée.



0
votes

Déclarez la bufferedreader en dehors du bloc d'essai et définissez-la sur NULL, utilisez enfin un blocage pour le fermer si ce n'est pas null. De même, la liste de fichiers est transmise par référence afin que toute modification apportée à celle-ci arrivera à l'objet que vous avez transmis de sorte qu'il n'y a pas besoin de le renvoyer également.

    public static ArrayList readFiletoArrayList(String fileName, ArrayList fileArrayList)
{
    fileArrayList.removeAll(fileArrayList);
    BufferedReader fileIn = null;
    try {
        //open the file for reading
        fileIn = new BufferedReader(new FileReader(fileName));

        // add line by line to array list, until end of file is reached
        // when buffered reader returns null (todo). 
        while(true){
                fileArrayList.add(fileIn.readLine());
            }
    }catch(IOException e){
        fileArrayList.removeAll(fileArrayList);  
    }finally
    {
       try
       {
           if(fillIn != null)
               fileIn.close();
       }
       catch(IOException e){}
    }
    return fileArrayList; //returned empty. Dealt with in calling code.
}


0 commentaires

1
votes

Ma manière préférée d'effectuer le nettoyage après une exception (lorsque le nettoyage peut également lancer une exception) consiste à mettre le code dans le bloc d'essai à l'intérieur d'un autre try / enfin, comme suit:

public static ArrayList readFiletoArrayList(String fileName, ArrayList fileArrayList) {
    fileArrayList.removeAll(fileArrayList);

    try {
        //open the file for reading
        BufferedReader fileIn = null;

        try {
            fileIn = new BufferedReader(new FileReader(fileName));
            // add line by line to array list, until end of file is reached
            // when buffered reader returns null (todo). 
            while(true){
                fileArrayList.add(fileIn.readLine());
            }
        } finally {
            if (fileIn != null) {
                fileIn.close();
            }
        }
    }catch(IOException e){
        fileArrayList.removeAll(fileArrayList);
        return fileArrayList; //returned empty. Dealt with in calling code. 
    }
}


1 commentaires

Cela a l'inconvénient d'avaler la mauvaise exception. Si la lecture en lecture échoue pour une raison quelconque, elle jette une exception IoException. Le fichier est ensuite fermé à l'intérieur du final. Si le fichier fermé échoue également, une nouvelle IoException est lancée et la première exception, avec un message d'erreur éventuellement précieux, est perdu.



0
votes

4 commentaires

Il me semblerait que si le dossier était ouvert pour écrire plutôt que de lire, une opération sûre nécessiterait que toute IOException qui se produit lors de la fermeture du fichier ne soit pas avalée, sauf s'il existait déjà une ioexception percolant la pile d'appels. Il peut être raisonnable d'avaler un IoException lancé par une opération de fermeture de fichier qui est elle-même dans un attrape (ioException e) , mais si le enfin est atteinte via une exécution de code normale, avaler un ioException sur la fermeture pourrait entraîner une croire à une manière erronée d'un fichier lorsqu'il n'était pas écrit lorsqu'il n'était pas.


@supercat: Vous avez raison - mais c'est la lecture de fichiers. L'écriture doit affleurer le décorateur (et ne pas compter sur la fermeture) - s'il y a un décorateur . Je passe par certaines particularités ici - injustement fermé


Le motif des exceptions de nettoyage éternuement est souvent appliqué sans tenir compte de ce que le nettoyage implique. Dans certains cas, ça va, mais comme habitude, cela semble dangereux. Quant à votre question liée (fermée), je vous suggère de commencer par un peu moins de backstory. Ce que vous voulez vraiment savoir (à partir de ce que je peux dire), c'est comment faire face à une exception projetée d'un constructeur qui est censé acquérir la propriété si un flux passé. Ma suggestion serait que de tels constructeurs clôturent le flux transmis s'ils lancent une exception, sinon être enveloppés dans une méthode d'usine qui le fait.


Bien que nécessaire, c'est un code laid. Ce qui devrait être quelques lignes est devenu un gâchis de champs avec un flux spaghetti piétonné. Et pour penser que toute cette complexité a été ajoutée pour des raisons de simplicité! Me fait savoir pour l'époque de l'assemblée.