Devo chiudere () sia FileReader che BufferedReader?


188

Sto leggendo un file locale usando un BufferedReader racchiuso in un FileReader:

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

Devo close()la FileReadercosì, o sarà la maniglia wrapper che? Ho visto codice in cui le persone fanno qualcosa del genere:

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

Questo metodo viene chiamato da un servlet e vorrei assicurarmi di non lasciare alcun handle aperto.


4
Sai, puoi semplicemente leggere la fonte per informazioni come questa. È tutto lì in src.zip nella directory di installazione di JDK, oppure puoi leggerlo online ad esempio docjar.com/html/api/java/io/BufferedReader.java.html
gustafc

50
Dire a qualcuno di leggere la fonte è peggio che dire "RTFM!". E se la fonte avesse un bug; implicitamente vogliamo sapere qual è il comportamento corretto ?
Raedwald,

1
Bene ... da questo punto di vista: puntare alle specifiche API non è poi migliore. Se l'origine non ha un bug che causa il comportamento che non si comporta come specificato nei documenti, non è possibile fare affidamento sui documenti. Quindi non c'è un buon modo per rispondere a una domanda del genere.
Atmocreations

@Atmocreations La prossima versione di manutenzione può correggere allegramente un bug su cui fare affidamento se si guarda alla fonte. Hai davvero bisogno di sapere qual è il comportamento documentato. Niente di male nel guardare la fonte, ovviamente, ma non puoi presumere che la fonte non cambierà. La modifica del comportamento documentato è in genere molto più grave della correzione di un bug.
James Moore,

Risposte:


202

no.

BufferedReader.close()

chiude il flusso in base a javadoc per BufferedReader e InputStreamReader

così come

FileReader.close()

lo fa.


12
A meno che il costruttore non BufferedReadergeneri un'eccezione. È più pulito solo per chiudere il flusso sottostante, anche se è necessario fare attenzione ai decoratori con altre risorse e buffering.
Tom Hawtin - tackline

9
Javadoc non dice se BufferedReader.close()chiude il lettore sottostante. La sua descrizione è semplicemente copiata da Reader.close(). Questo può essere il comportamento effettivo in pratica, ma non è documentato.
John Kugelman,

3
Se il comportamento effettivo fosse diverso, avrebbe dovuto essere documentato come tale. Altrimenti la documentazione è inutile. Il programmatore dovrebbe essere in grado di considerare la documentazione come completa e specifica.
Atmocreations

6
Non importa se la documentazione reale avrebbe dovuto essere cambiata o non avrebbe dovuto essere cambiata, Reader#close()javadoc non dice se chiude o meno il suo wrapper Reader o meno. Tutto ciò che dice è collegato a ciò Closes the stream and releases any system resources associated with it.che non è abbastanza esplicito da dire che chiude o non chiude la risorsa. 'Rilascia la risorsa' potrebbe anche rimuovere qualsiasi riferimento alla risorsa nel BufferedReader ... il che significherebbe che la risorsa non è chiusa.
searchengine27,

99

Come altri hanno sottolineato, è sufficiente chiudere l'involucro esterno.

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

Esiste una probabilità molto ridotta che ciò possa perdere un handle di file se il BufferedReadercostruttore ha generato un'eccezione (ad esempio OutOfMemoryError). Se la tua app è in questo stato, quanto deve essere accurata la tua pulizia potrebbe dipendere da quanto sia fondamentale non privare il sistema operativo delle risorse che potrebbe voler allocare ad altri programmi.

L' interfaccia Closeable può essere utilizzata se è probabile che un costruttore wrapper non riesca in Java 5 o 6:

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

Il codice Java 7 dovrebbe usare il modello try-with-resources :

try (Reader reader = new FileReader(fileName);
    BufferedReader buffered = new BufferedReader(reader)) {
  // TODO: input
}

1
"Il codice Java 7 dovrebbe usare il modello try-with-resources". Grazie, è esattamente quello che stavo cercando. Questa soluzione è stata scritta nel '09, quindi il paradigma di prova con risorse dovrebbe probabilmente essere la nuova raccomandazione. Inoltre, offre una risposta migliore al PO rispetto alla risposta accettata e votata più in alto.
venerdì

5

Secondo la fonte BufferedReader, in questo caso bReader.close chiama fReader.close quindi tecnicamente non è necessario chiamare quest'ultimo.


Dato che c'è documentazione che spiega come dovrebbe essere usato, dovresti prima guardare la documentazione - ogni deviazione nel codice è un bug.
hmijail piange le dimissioni dal

5

Il codice sorgente per BufferedReader mostra che il sottostante è chiuso quando si chiude BufferedReader.


1
Voglio davvero dare un pollice in alto per il collegamento a qualcosa di concreto, ma questo si riferisce solo all'implementazione di OpenJDK, e poiché i JavaDocs non sono chiari Reader#close(), ciò non fornisce prove concrete che Oracle JDK, ad esempio, sia implementato in un moda simile.
searchengine27,

4

Dopo aver verificato il codice sorgente, ho scoperto che per l'esempio:

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

il metodo close () sull'oggetto BufferedReader chiamerebbe il metodo abstract close () della classe Reader che alla fine chiamerebbe il metodo implementato nella classe InputStreamReader , che quindi chiude l' oggetto InputStream .

Pertanto, è sufficiente solo bReader.close ().


4
Ciò che il codice sorgente mostra non è citabile come riferimento. È ciò che dice la specifica , in questo caso Javadoc, su cui si può fare affidamento.
Marchese di Lorne,

1

A partire da Java 7 è possibile utilizzare l' istruzione try-with-resources

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

Poiché l' BufferedReaderistanza viene dichiarata in un'istruzione try-with-resource, verrà chiusa indipendentemente dal fatto che l'istruzione try venga completata normalmente o bruscamente. Quindi non è necessario chiuderlo da soli finallynell'istruzione. (Questo è anche il caso delle dichiarazioni di risorse nidificate)

Questo è il modo consigliato per lavorare con le risorse, vedere la documentazione per informazioni più dettagliate


Questo è quasi identico alla risposta di @ mcdowell del 2009, che copre anche alcuni casi limite che potrebbero verificarsi.
venerdì

0

Devi solo chiudere bufferedReader, ad esempio reader.close () e funzionerà benissimo.


0

Sono in ritardo, ma:

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;
        }
    }
}

Eeeeh che non risponde alla sua domanda? Lei / Lui chiede se è necessario chiudere FileReader e BufferedReader non un codice di esempio.
TornaxO7

@ TornaxO7 no, non è un codice di esempio. Ho appena scritto parte del codice sorgente Java. Quindi, se fai clic su alcune funzioni di BufferedReader con il tasto ctrl / cmd (dipende dall'IDE) puoi vedere il codice sorgente di BufferedReader e puoi trovare quel frammento di codice. Quindi, come puoi vedere BufferedReader basta chiudere FileReader da solo ('in' è FileReader in questo caso, quindi, quando chiami bufferReader.close () chiama in.close () all'interno, esattamente nel metodo bufferReader.close)
Dmitry Gashko

0

È Do not necessario chiudere il lettore / scrittore avvolto.

Se hai dato un'occhiata ai documenti ( Reader.close(), Writer.close()), vedrai che in Reader.close()esso dice:

Chiude lo stream e rilascia tutte le risorse di sistema ad esso associate.

Il che dice semplicemente che "libera tutte le risorse di sistema ad esso associate ". Anche se non conferma .. ti dà una spinta per iniziare a sembrare più profondo. e se ci vai Writer.close()afferma solo che si chiude da solo.

In questi casi, ci riferiamo a OpenJDK per dare un'occhiata al codice sorgente.

A BufferedWriter Line 265 vedrai out.close(). Quindi non si chiude da solo .. È qualcos'altro. Se cerchi le occorrenze di " out" nella classe noterai che nel costruttore alla riga 87 che outè lo scrittore la classe si sposta dove chiama un altro costruttore e quindi assegna il outparametro alla propria outvariabile.

Quindi .. E gli altri? Puoi vedere un codice simile su BufferedReader Line 514 , BufferedInputStream Line 468 e InputStreamReader Line 199 . Altri non lo so, ma questo dovrebbe essere sufficiente per supporre che lo facciano.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.