J'écris un morceau de code:
OutputStream outputStream = new FileOutputStream(createdFile);
GZIPOutputStream gzipOutputStream = new GZIPOutputStream(outputStream);
BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(gzipOutputStream));
Dois-je fermer chaque flux ou écrivain comme suit?
gzipOutputStream.close();
bw.close();
outputStream.close();
Ou est-ce que la fermeture du dernier flux sera bien?
bw.close();
java
file-io
outputstream
writer
Adon Smith
la source
la source
BufferedWriter
il peut avoir besoin d'écrire des données tamponnées dans le flux sous-jacent, qui dans votre exemple est déjà fermé. Éviter ces problèmes est un autre avantage des approches d' essai avec les ressources présentées dans les réponses.Réponses:
En supposant que tous les flux sont créés correctement, oui, la simple fermeture
bw
convient parfaitement à ces implémentations de flux ; mais c'est une grande hypothèse.J'utiliserais try-with-resources ( tutoriel ) afin que tout problème de construction des flux suivants qui lancent des exceptions ne laisse pas les flux précédents en suspens, et vous n'avez donc pas à compter sur l'implémentation du flux ayant l'appel pour fermer le flux sous-jacent:
Notez que vous n'appelez plus
close
du tout.Remarque importante : pour que try-with-resources les ferme, vous devez affecter les flux aux variables lorsque vous les ouvrez, vous ne pouvez pas utiliser l'imbrication. Si vous utilisez l'imbrication, une exception lors de la construction de l'un des derniers flux (par exemple
GZIPOutputStream
) laissera ouvert tout flux construit par les appels imbriqués à l'intérieur. À partir de JLS §14.20.3 :Notez le mot «variables» (je souligne) .
Par exemple, ne faites pas ceci:
... car une exception du
GZIPOutputStream(OutputStream)
constructeur (qui dit qu'il peut lancerIOException
et écrit un en-tête dans le flux sous-jacent) laisseraitFileOutputStream
ouvert. Étant donné que certaines ressources ont des constructeurs qui peuvent lancer et d'autres pas, c'est une bonne habitude de les énumérer séparément.Nous pouvons revérifier notre interprétation de cette section JLS avec ce programme:
... qui a la sortie:
Notez qu'il n'y a pas d'appels
close
là-bas.Si nous corrigeons
main
:puis nous recevons les
close
appels appropriés :(Oui, deux appels à
InnerMost#close
est correct; l'un provient deMiddle
, l'autre de try-with-resources.)la source
java.io
plus. Certains flux - généralisation, certaines ressources - proviennent des constructeurs. Donc, s'assurer que plusieurs ressources sont ouvertes individuellement afin qu'elles puissent être fermées de manière fiable si une ressource suivante est lancée est juste une bonne habitude, à mon avis. Vous pouvez choisir de ne pas le faire si vous n'êtes pas d'accord, c'est très bien.GZIPOutputStream
le constructeur de s écrit un en-tête dans le flux. Et ainsi il peut jeter. Alors maintenant, la position est de savoir si je pense qu'il vaut la peine d' essayer de fermer le flux après avoir écrit jeté. Ouais: je l'ai ouvert, je devrais au moins essayer de le fermer.Vous pouvez fermer le flux le plus externe, en fait vous n'avez pas besoin de conserver tous les flux encapsulés et vous pouvez utiliser Java 7 try-with-resources.
Si vous vous abonnez à YAGNI, ou si vous n'en avez pas besoin, vous ne devriez ajouter que le code dont vous avez réellement besoin. Vous ne devriez pas ajouter de code dont vous pensez avoir besoin, mais en réalité, cela ne fait rien d'utile.
Prenez cet exemple et imaginez ce qui pourrait mal tourner si vous ne le faisiez pas et quel en serait l'impact?
Commençons par FileOutputStream qui appelle
open
à faire tout le vrai travail.Si le fichier n'est pas trouvé, il n'y a pas de ressource sous-jacente à fermer, donc le fermer ne fera aucune différence. Si le fichier existe, il doit lancer une exception FileNotFoundException. Il n'y a donc rien à gagner en essayant de fermer la ressource à partir de cette seule ligne.
La raison pour laquelle vous devez fermer le fichier est lorsque le fichier est ouvert avec succès, mais vous obtenez plus tard une erreur.
Regardons le prochain flux
GZIPOutputStream
Il y a du code qui peut lever une exception
Cela écrit l'en-tête du fichier. Maintenant, il serait très inhabituel pour vous de pouvoir ouvrir un fichier pour l'écriture mais de ne pas pouvoir y écrire même 8 octets, mais imaginons que cela puisse arriver et nous ne fermons pas le fichier par la suite. Qu'arrive-t-il à un fichier s'il n'est pas fermé?
Vous n'obtenez pas d'écritures non vidées, elles sont supprimées et dans ce cas, il n'y a pas d'octets écrits avec succès dans le flux qui n'est de toute façon pas mis en mémoire tampon à ce stade. Mais un fichier qui n'est pas fermé ne vit pas éternellement, FileOutputStream a
Si vous ne fermez pas du tout un fichier, il se ferme de toute façon, mais pas immédiatement (et comme je l'ai dit, les données qui sont laissées dans un tampon seront perdues de cette façon, mais il n'y en a pas à ce stade)
Quelle est la conséquence de ne pas fermer le dossier immédiatement? Dans des conditions normales, vous risquez de perdre certaines données et vous risquez de manquer de descripteurs de fichiers. Mais si vous avez un système où vous pouvez créer des fichiers mais que vous ne pouvez rien y écrire, vous avez un problème plus grave. c'est-à-dire qu'il est difficile d'imaginer pourquoi vous essayez à plusieurs reprises de créer ce fichier malgré le fait que vous échouez.
OutputStreamWriter et BufferedWriter ne lancent pas d'exception IOException dans leurs constructeurs, de sorte que le problème qu'ils provoqueraient n'est pas clair. Dans le cas de BufferedWriter, vous pouvez obtenir une OutOfMemoryError. Dans ce cas, il déclenchera immédiatement un GC qui, comme nous l'avons vu, fermera quand même le fichier.
la source
GZIPOutputStream(OutputStream)
documentsIOException
et, en regardant la source, écrit en fait un en-tête. Ce n'est donc pas théorique, ce constructeur peut lancer. Vous pouvez penser qu'il est normal de laisser le sous-jacentFileOutputStream
ouvert après avoir écrit dessus. Je ne.Si tous les flux ont été instanciés, la fermeture uniquement du flux externe est très bien.
La documentation sur l'
Closeable
interface indique que la méthode close:Les ressources du système de libération comprennent des flux de fermeture.
Il déclare également que:
Donc, si vous les fermez explicitement par la suite, il ne se passera rien de mal.
la source
Je préfère utiliser la
try(...)
syntaxe (Java 7), par exemplela source
Ce sera bien si vous ne fermez que le dernier flux - l'appel de fermeture sera également envoyé aux flux sous-jacents.
la source
Non, le niveau le plus élevé
Stream
oureader
garantira que tous les flux / lecteurs sous-jacents sont fermés.Vérifiez la mise en œuvre de la
close()
méthode de votre flux de niveau supérieur.la source
Dans Java 7, il existe une fonctionnalité try-with-resources . Vous n'avez pas besoin de fermer explicitement vos flux, il s'en chargera.
la source