Muss ich sowohl FileReader als auch BufferedReader schließen ()?

188

Ich lese eine lokale Datei mit einem BufferedReader, der um einen FileReader gewickelt ist:

BufferedReader reader = new BufferedReader(new FileReader(fileName));
// read the file
// (error handling snipped)
reader.close();

Muss ich close()das FileReaderauch oder wird der Wrapper damit umgehen? Ich habe Code gesehen, in dem Leute so etwas tun:

FileReader fReader = new FileReader(fileName);
BufferedReader bReader = new BufferedReader(fReader);
// read the file
// (error handling snipped)
bReader.close();
fReader.close();

Diese Methode wird von einem Servlet aufgerufen, und ich möchte sicherstellen, dass keine Handles offen bleiben.

Zilk
quelle
4
Weißt du, du kannst einfach die Quelle für solche Informationen lesen. Es ist alles in src.zip im JDK-Installationsverzeichnis enthalten, oder Sie können es online unter beispielsweise docjar.com/html/api/java/io/BufferedReader.java.html
gustafc
50
Jemandem zu sagen, er solle die Quelle lesen, ist schlimmer als "RTFM!". Und was ist, wenn die Quelle einen Fehler hat? implizit wollen wir wissen, was das richtige Verhalten ist?
Raedwald
1
Nun ... aus dieser Sicht: Das Zeigen auf API-Spezifikationen ist dann nicht besser. Wenn die Quelle keinen Fehler aufweist, der dazu führt, dass sie sich nicht wie in den Dokumenten angegeben verhält, können Sie sich nicht auf die Dokumente verlassen. Es gibt also keine gute Möglichkeit, eine solche Frage zu beantworten.
Atmocreations
@Atmocreations Die nächste Wartungsversion kann einen Fehler, auf den Sie sich verlassen, fröhlich beheben, wenn Sie sich nur die Quelle ansehen. Sie müssen wirklich wissen, was das dokumentierte Verhalten ist. Natürlich ist nichts falsch daran, die Quelle zu betrachten, aber Sie können nicht davon ausgehen, dass sich die Quelle nicht ändert. Das Ändern des dokumentierten Verhaltens ist normalerweise viel umfangreicher als das Beheben eines Fehlers.
James Moore

Antworten:

202

Nein.

BufferedReader.close()

Schließt den Stream gemäß Javadoc für BufferedReader und InputStreamReader

ebenso gut wie

FileReader.close()

tut.

Atmocreations
quelle
12
Es sei denn, der Konstruktor BufferedReaderlöst eine Ausnahme aus. Es ist sauberer, nur um den zugrunde liegenden Stream zu schließen, obwohl Sie auf Dekorateure mit anderen Ressourcen und Pufferung achten müssen.
Tom Hawtin - Tackline
9
Der Javadoc sagt nicht, ob BufferedReader.close()der zugrunde liegende Leser geschlossen wird. Die Beschreibung wird einfach von kopiert Reader.close(). Dies mag das tatsächliche Verhalten in der Praxis sein, ist jedoch nicht dokumentiert.
John Kugelman
3
Wenn das tatsächliche Verhalten anders war, sollte es als solches dokumentiert worden sein. Ansonsten ist die Dokumentation unbrauchbar. Der Programmierer sollte in der Lage sein, die Dokumentation als vollständig und spezifisch zu betrachten.
Atmocreations
6
Es spielt keine Rolle, ob die eigentliche Dokumentation hätte geändert werden sollen oder nicht, Reader#close()die Javadocs sagen nicht, ob sie den verpackten Reader schließen oder nicht. Alles, was damit in Verbindung steht Closes the stream and releases any system resources associated with it., ist nicht explizit genug, um zu sagen, dass die Ressource geschlossen wird oder nicht. 'Ressource freigeben' kann genauso gut einen Verweis auf die Ressource im BufferedReader entfernen ... was bedeuten würde, dass die Ressource nicht geschlossen ist.
Searchengine27
99

Wie andere bereits betont haben, müssen Sie nur die äußere Hülle schließen.

BufferedReader reader = new BufferedReader(new FileReader(fileName));

Es besteht eine sehr geringe Wahrscheinlichkeit, dass dadurch ein Dateihandle verloren geht, wenn der BufferedReaderKonstruktor eine Ausnahme auslöst (zOutOfMemoryError . ). Wenn sich Ihre App in diesem Zustand befindet, hängt die Sorgfalt bei der Bereinigung möglicherweise davon ab, wie wichtig es ist, dass Sie dem Betriebssystem nicht die Ressourcen entziehen, die es möglicherweise anderen Programmen zuweisen möchte.

Die Closeable- Schnittstelle kann verwendet werden, wenn ein Wrapper-Konstruktor in Java 5 oder 6 wahrscheinlich ausfällt:

Reader reader = new FileReader(fileName);
Closeable resource = reader;
try {
  BufferedReader buffered = new BufferedReader(reader);
  resource = buffered;
  // TODO: input
} finally {
  resource.close();
}

Java 7-Code sollte das Muster " Try-with-Resources" verwenden :

try (Reader reader = new FileReader(fileName);
    BufferedReader buffered = new BufferedReader(reader)) {
  // TODO: input
}
McDowell
quelle
1
"Java 7-Code sollte das Try-with-Resources-Muster verwenden". Danke, genau das habe ich gesucht. Diese Lösung wurde '09 geschrieben, daher sollte das Paradigma des Versuchs mit Ressourcen wahrscheinlich die neue Empfehlung sein. Darüber hinaus bietet es dem OP eine bessere Antwort als die akzeptierte und höher bewertete Antwort.
Tresf
5

Laut BufferedReader-Quelle ruft bReader.close in diesem Fall fReader.close auf, sodass Sie letzteres technisch nicht aufrufen müssen.

Csaba_H
quelle
Da es eine Dokumentation gibt, in der erklärt wird, wie es verwendet werden soll, sollten Sie sich zuerst die Dokumentation ansehen - jede Abweichung im Code ist ein Fehler.
Hmijail trauert um die Rücktritte
5

Der Quellcode für BufferedReader zeigt, dass der Basiswert geschlossen wird, wenn Sie den BufferedReader schließen.

Brian Agnew
quelle
1
Ich möchte dem wirklich einen Daumen hoch geben, um auf etwas Konkretes zu verlinken, aber dies bezieht sich nur auf die OpenJDK-Implementierung, und da die JavaDocs unklar sind Reader#close(), liefert dies keinen konkreten Beweis dafür, dass das Oracle JDK beispielsweise in a implementiert ist ähnliche Mode.
Searchengine27
4

Nachdem ich den Quellcode überprüft hatte, stellte ich Folgendes fest:

FileReader fReader = new FileReader(fileName);
BufferedReader bReader = new BufferedReader(fReader);

Die close () -Methode für das BufferedReader- Objekt würde die abstrakte close () -Methode der Reader- Klasse aufrufen, die letztendlich die implementierte Methode in der InputStreamReader- Klasse aufruft , die dann das InputStream- Objekt schließt .

Es ist also nur bReader.close () ausreichend.

Anup Verma
quelle
4
Was der Quellcode anzeigt, kann nicht als Referenz zitiert werden. Darauf kann man sich in der Spezifikation verlassen , in diesem Fall auf den Javadoc.
Marquis von Lorne
1

Ab Java 7 können Sie die Anweisung try-with-resources verwenden

try (BufferedReader br = new BufferedReader(new FileReader(path))) {
    return br.readLine();
}

Da die BufferedReaderInstanz in einer Try-with-Resource-Anweisung deklariert ist, wird sie geschlossen, unabhängig davon, ob die try-Anweisung normal oder abrupt ausgeführt wird. Sie müssen es also nicht selbst in der finallyAnweisung schließen. (Dies ist auch bei verschachtelten Ressourcenanweisungen der Fall.)

Dies ist die empfohlene Methode zum Arbeiten mit Ressourcen. Weitere Informationen finden Sie in der Dokumentation

Claudiu
quelle
Dies ist nahezu identisch mit der Antwort von @ mcdowell aus dem Jahr 2009, in der auch einige Randfälle behandelt werden, die auftreten können.
Tresf
0

Sie müssen nur den bufferedReader, dh reader.close (), schließen, und es funktioniert einwandfrei.

Jitendra
quelle
0

Ich bin spät dran, aber:

BufferReader.java:

public BufferedReader(Reader in) {
  this(in, defaultCharBufferSize);
}

(...)

public void close() throws IOException {
    synchronized (lock) {
        if (in == null)
            return;
        try {
            in.close();
        } finally {
            in = null;
            cb = null;
        }
    }
}
Dmitry Gashko
quelle
Eeeeh, der seine / ihre Frage nicht beantwortet? Sie / Er fragt , ob es notwendig Filereader und BufferedReader kein Beispiel - Code zu schließen.
TornaxO7
@ TornaxO7 nein, es ist kein Beispielcode. Ich habe gerade einen Teil des Java-Quellcodes geschrieben. Wenn Sie also mit der Strg / cmd-Taste auf eine Funktion von BufferedReader klicken (abhängig von der IDE), wird der Quellcode von BufferedReader angezeigt und das Codefragment gefunden. Wie Sie sehen können, schließen Sie BufferedReader einfach FileReader selbst ('in' ist in diesem Fall FileReader. Wenn Sie bufferReader.close () aufrufen, ruft es in.close () auf, genau in der bufferReader.close-Methode)
Dmitry Gashko
0

Sie nicht den verpackten Leser / Schreiber schließen müssen.

Wenn Sie sich die Dokumente ( Reader.close(), Writer.close()) angesehen haben, sehen Sie, dass Reader.close()darin steht:

Schließt den Stream und gibt alle damit verbundenen Systemressourcen frei.

Welche sagt nur , dass es „keine Systemressourcen freigibt assoziiert mit ihm“. Auch wenn es nicht bestätigt wird, gibt es Ihnen einen Anstoß, tiefer zu schauen. und wenn Sie dorthin gehen, heißt Writer.close()es nur, dass es sich selbst schließt.

In solchen Fällen verweisen wir auf OpenJDK , um einen Blick auf den Quellcode zu werfen.

Bei BufferedWriter Line 265 sehen Sie out.close(). Es schließt sich also nicht von selbst. Es ist etwas anderes. Wenn Sie die Klasse nach Vorkommen von " out" durchsuchen, werden Sie feststellen, dass im Konstruktor in Zeile 87 , outder der Writer ist, die Klasse umschließt, wo sie einen anderen Konstruktor aufruft und dann outihrer eigenen outVariablen Parameter zuweist .

Also .. Was ist mit anderen? Sie können ähnlichen Code in BufferedReader Line 514 , BufferedInputStream Line 468 und InputStreamReader Line 199 sehen . Andere kenne ich nicht, aber das sollte ausreichen, um anzunehmen, dass sie es tun.

Omar Abdul'Azeez
quelle