Czy muszę zamykać () zarówno FileReader, jak i BufferedReader?

188

Czytam plik lokalny za pomocą BufferedReader owiniętego wokół FileReader:

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

Czy muszę , jak również, czy będzie uchwyt wrapper że? Widziałem kod, w którym ludzie robią coś takiego:close()FileReader

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

Ta metoda jest wywoływana z serwletu i chciałbym się upewnić, że nie zostawię otwartych uchwytów.

Zilk
źródło
4
Wiesz, możesz po prostu przeczytać źródło takich informacji. Wszystko znajduje się w pliku src.zip w katalogu instalacyjnym JDK lub można go przeczytać online na przykład na stronie docjar.com/html/api/java/io/BufferedReader.java.html
gustafc
50
Mówienie komuś, by przeczytało źródło, jest gorsze niż mówienie „RTFM!”. A jeśli źródło ma błąd; domyślnie chcemy wiedzieć, jakie jest prawidłowe zachowanie?
Raedwald
1
Cóż ... z tego punktu widzenia: wskazanie specyfikacji API nie jest lepsze. Jeśli źródło nie zawiera błędu powodującego, że nie zachowuje się tak, jak podano w dokumentach, nie można polegać na dokumentach. Więc nie ma dobrego sposobu na odpowiedź na takie pytanie.
Atmocreations,
@Atmocreations Kolejne wydanie serwisowe może z radością naprawić błąd, na którym można polegać, jeśli spojrzysz na źródło. Naprawdę musisz wiedzieć, jakie jest udokumentowane zachowanie. Oczywiście nie ma nic złego w patrzeniu na źródło, ale nie możesz zakładać, że źródło się nie zmieni. Zmiana udokumentowanego zachowania jest zwykle znacznie większym problemem niż naprawienie błędu.
James Moore

Odpowiedzi:

202

Nie.

BufferedReader.close()

zamyka strumień zgodnie z javadoc dla BufferedReader i InputStreamReader

jak również

FileReader.close()

robi.

Atokreacje
źródło
12
Chyba że konstruktor BufferedReaderzgłosi wyjątek. Czystsze jest tylko zamknięcie podstawowego strumienia, chociaż musisz uważać na dekoratorów z innymi zasobami i buforowaniem.
Tom Hawtin - tackline
9
Javadoc nie mówi, czy BufferedReader.close()zamyka podstawowy czytnik. Jego opis jest po prostu skopiowany z Reader.close(). To może być rzeczywiste zachowanie w praktyce, ale nie jest to udokumentowane.
John Kugelman
3
Jeśli rzeczywiste zachowanie było inne, powinno to zostać udokumentowane jako takie. W przeciwnym razie dokumentacja jest bezużyteczna. Programista powinien być w stanie uznać dokumentację za kompletną i szczegółową.
Atmocreations,
6
Nie ma znaczenia, czy rzeczywista dokumentacja powinna zostać zmieniona, czy nie powinna była zostać zmieniona, Reader#close()javadoc nie mówi, czy zamyka, czy jest owinięty Czytnik, czy nie. Wszystko, Closes the stream and releases any system resources associated with it.co jest z tym związane, to to, że nie jest wystarczająco wyraźne, aby powiedzieć, że zamyka lub nie zamyka zasobu. „Zwolnij zasób” równie dobrze może usuwać wszelkie odwołania do zasobu w BufferedReader ... co oznaczałoby, że zasób nie jest zamknięty.
searchengine27
99

Jak zauważyli inni, wystarczy zamknąć zewnętrzne opakowanie.

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

Istnieje bardzo niewielka szansa, że ​​może to spowodować wyciek uchwytu pliku, jeśli BufferedReaderkonstruktor zgłosi wyjątek (npOutOfMemoryError .). Jeśli aplikacja jest w tym stanie, to, jak ostrożne musi być czyszczenie, może zależeć od tego, jak ważne jest, aby nie pozbawiać systemu operacyjnego zasobów, które może chcieć przydzielić innym programom.

Zamykane interfejs może być stosowane, jeżeli konstruktor wrapper może zawieść w Java 5 lub 6:

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

Kod Java 7 powinien używać wzorca try-with-resources :

try (Reader reader = new FileReader(fileName);
    BufferedReader buffered = new BufferedReader(reader)) {
  // TODO: input
}
McDowell
źródło
1
„Kod Java 7 powinien używać wzorca try-with-resources”. Dzięki, właśnie tego szukałem. To rozwiązanie zostało napisane w 2009 roku, więc paradygmat try-with-resources powinien być prawdopodobnie nową rekomendacją. Ponadto oferuje lepszą odpowiedź dla PO niż zaakceptowana i wyżej głosowana odpowiedź.
tresf
5

Według źródła BufferedReader, w tym przypadku bReader.close wywołuje fReader.close, więc technicznie nie trzeba wywoływać tego ostatniego.

Csaba_H
źródło
Biorąc pod uwagę, że istnieje dokumentacja wyjaśniająca, w jaki sposób należy go używać, najpierw należy zapoznać się z dokumentacją - każde odchylenie w kodzie jest błędem.
Hmijail opłakuje powrót
5

Kod źródłowy dla BufferedReader pokazuje, że instrument bazowy jest zamknięty po zamknięciu BufferedReader.

Brian Agnew
źródło
1
Naprawdę chcę dać aprobatę za połączenie z czymś konkretnym, ale odnosi się to tylko do implementacji OpenJDK, a ponieważ JavaDocs są niejasne Reader#close(), nie zapewnia to konkretnych dowodów na to, że Oracle JDK, na przykład, jest implementowany w podobna moda.
searchengine27
4

Po sprawdzeniu kodu źródłowego znalazłem to na przykład:

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

metoda close () na obiekcie BufferedReader wywołałaby abstrakcyjną metodę close () klasy Reader, która ostatecznie wywołałaby zaimplementowaną metodę w klasie InputStreamReader , która następnie zamyka obiekt InputStream .

Tak więc wystarczy tylko bReader.close ().

Anup Verma
źródło
4
To, co pokazuje kod źródłowy, nie jest cytowane jako odniesienie. Tak mówi specyfikacja , w tym przypadku Javadoc, na którym można polegać.
Markiz Lorne
1

Począwszy od wersji Java 7 można użyć instrukcji try-with-resources

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

Ponieważ BufferedReaderinstancja jest zadeklarowana w instrukcji try-with-resource, zostanie zamknięta niezależnie od tego, czy instrukcja try zakończy się normalnie czy nagle. Więc nie musisz go sam zamykać w finallywyciągu. (Dotyczy to również zagnieżdżonych instrukcji zasobów)

Jest to zalecany sposób pracy z zasobami, więcej informacji można znaleźć w dokumentacji

Claudiu
źródło
Jest to prawie identyczne z odpowiedzią @ mcdowell z 2009 roku, która obejmuje również niektóre problemy, które mogą wystąpić.
tresf
0

Musisz tylko zamknąć bufferedReader tj. Reader.close () i będzie działał dobrze.

Jitendra
źródło
0

Jestem spóźniony, ale:

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;
        }
    }
}
Dmitrij Gashko
źródło
Eeeeh, który nie odpowiada na jego pytanie? Pyta, czy konieczne jest zamknięcie FileReadera i BufferedReadera, a nie przykładowego kodu.
TornaxO7
@ TornaxO7 nie, to nie jest przykładowy kod. Właśnie napisałem część kodu źródłowego Java. Tak więc, jeśli klikniesz na funkcję BufferedReadera za pomocą klawisza ctrl / cmd (zależy od IDE), zobaczysz kod źródłowy BufferedReadera i możesz znaleźć ten fragment kodu. Tak więc, jak widać BufferedReader, wystarczy zamknąć FileReader sam w sobie (w tym przypadku FileReader w tym przypadku, więc kiedy wywołujesz bufferReader.close (), wywołuje on in.close () wewnątrz, dokładnie w metodzie bufferReader.close)
Dmitry Gashko
0

Ty Nie trzeba zamknąć owinięte odczytującego / zapisującego.

Jeśli spojrzałeś na dokumenty ( Reader.close(), Writer.close()), zobaczysz, że w Reader.close()nim jest napisane:

Zamyka strumień i uwalnia wszelkie związane z nim zasoby systemowe.

Co tylko mówi, że „uwalnia wszelkie związane z tym zasoby systemowe ”. Mimo że nie potwierdza ... daje ci ochotę zacząć szukać głębiej. a jeśli pójdziesz doWriter.close() niego to tylko stwierdza, że ​​się zamyka.

W takich przypadkach odsyłamy do OpenJDK, aby spojrzeć na kod źródłowy.

W BufferedWriter Line 265 zobaczysz out.close(). Więc to się nie zamyka ... To coś innego. Jeśli przeszukasz klasę pod kątem występowania „ out”, zauważysz, że w konstruktorze w linii 87, która outjest pisarzem, klasa zawija się tam, gdzie wywołuje innego konstruktora, a następnie przypisuje outparametr do własnej outzmiennej.

Więc .. Co z innymi? Podobny kod można zobaczyć w BufferedReader Line 514 , BufferedInputStream Line 468 i InputStreamReader Line 199 . Inni nie znam, ale to powinno wystarczyć, by założyć, że tak.

Omar Abdul'Azeez
źródło