217

I'm reading a local file using a BufferedReader wrapped around a FileReader:

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

Do I need to close() the FileReader as well, or will the wrapper handle that? I've seen code where people do something like this:

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

This method is called from a servlet, and I'd like to make sure I don't leave any handles open.

Alberto Zaccagni
  • 30,779
  • 11
  • 72
  • 106
Zilk
  • 8,917
  • 7
  • 36
  • 44
  • 5
    Y'know, you can just read the source for info like this. It's all there in src.zip in the JDK installation directory, or you can read it online at for example http://www.docjar.com/html/api/java/io/BufferedReader.java.html – gustafc Sep 07 '09 at 10:46
  • 64
    Telling someone to read the source is worse than saying "RTFM!". And what if the source has a bug; implicitly we want to know what the *correct* behaviour is? – Raedwald Jul 05 '13 at 11:48
  • 2
    Well... from this point of view: pointing to API specs isn't any better then. If the source hasn't a bug causing that it does not behave like it is specified in the docs, you cannot rely the docs. So there's no good way to answer such a question. – Atmocreations Sep 18 '15 at 07:40
  • @Atmocreations The next maintenance release can cheerfully fix a bug that you rely on if you just look at the source. You really do need to know what the documented behavior is. Nothing wrong in looking at the source, of course, but you can't assume the source won't change. Changing documented behavior is usually a _much_ bigger deal than fixing a bug. – James Moore Apr 11 '20 at 16:09

10 Answers10

220

no.

BufferedReader.close()

closes the stream according to javadoc for BufferedReader and InputStreamReader

as well as

FileReader.close()

does.

Chuck L
  • 1,026
  • 10
  • 23
Atmocreations
  • 9,923
  • 15
  • 67
  • 102
  • 14
    Unless the constructor to `BufferedReader` throws an exception. It's cleaner just to close the underlying stream, although you need to watch out for decorators with other resources and buffering. – Tom Hawtin - tackline Sep 07 '09 at 14:55
  • 10
    The Javadoc does not say whether `BufferedReader.close()` closes the underlying reader. Its description is simply copied from `Reader.close()`. This may be the actual behavior in practice, but it's not documented. – John Kugelman Mar 30 '15 at 22:12
  • 4
    If the actual behaviour was different, then it should have been documented as such. Otherwise the documentation is useless. The programmer should be able to consider the documentation as complete and specific. – Atmocreations Apr 07 '15 at 06:28
  • 8
    It doesn't matter whether the actual documentation should have been changed or shouldn't have been changed, `Reader#close()`'s javadoc's don't say whether or not it closes it's wrapped Reader or not. All it says related to that is `Closes the stream and releases any system resources associated with it.` which is not explicit enough to say that it does or does not close the resource. 'Release the resource' may just as well be removing any reference to the resource in the BufferedReader...which would mean the resource is not closed. – searchengine27 Oct 29 '15 at 22:12
  • I think the term 'system resource' is explicit maybe a bit technical / old fashioned way to qualify a resource which is not managed by the runtime environment (here the JVM) but by the underlying 'system' (which also manages the JVM's process) – flash42 Mar 18 '21 at 06:31
  • I have found an official Java code example where they close both the FileReader and the BufferedReader. But why? See second example on this page https://docs.oracle.com/javase/tutorial/essential/exceptions/tryResourceClose.html – zomega Apr 14 '22 at 08:07
114

As others have pointed out, you only need to close the outer wrapper.

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

There is a very slim chance that this could leak a file handle if the BufferedReader constructor threw an exception (e.g. OutOfMemoryError). If your app is in this state, how careful your clean up needs to be might depend on how critical it is that you don't deprive the OS of resources it might want to allocate to other programs.

The Closeable interface can be used if a wrapper constructor is likely to fail in Java 5 or 6:

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

Java 7 code should use the try-with-resources pattern:

try (Reader reader = new FileReader(fileName);
    BufferedReader buffered = new BufferedReader(reader)) {
  // TODO: input
}
McDowell
  • 107,573
  • 31
  • 204
  • 267
  • 3
    "Java 7 code should use the try-with-resources pattern". Thanks, that's exactly what I was looking for. This solution was written in '09, so the try-with-resources paradigm should probably be the new recommendation. Furthemore, it offers a better answer to the OP over the accepted and higher voted answer. – tresf Feb 10 '20 at 18:48
  • 1
    @tresf just searched for 10 minutes trying to find this answer, I couldn't agree more - showing how to open the Filereader so you can close it later is key – cjnash Dec 03 '20 at 04:29
7

According to BufferedReader source, in this case bReader.close call fReader.close so technically you do not have to call the latter.

Csaba_H
  • 8,215
  • 1
  • 41
  • 42
  • Given that there is documentation explaining how it should be used, you should look at the documentation first – any deviation in the code is a bug. – hmijail Jul 01 '19 at 13:26
7

The source code for BufferedReader shows that the underlying is closed when you close the BufferedReader.

Brian Agnew
  • 268,207
  • 37
  • 334
  • 440
  • 2
    I really want to give this a thumbs up for linking to something concrete, but this only refers to the OpenJDK implementation, and since the JavaDocs are unclear for `Reader#close()`, this does not provide concrete evidence that the Oracle JDK, for example, is implemented in a similar fashion. – searchengine27 Oct 29 '15 at 22:15
7

After checking the source code, I found that for the example:

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

the close() method on BufferedReader object would call the abstract close() method of Reader class which would ultimately call the implemented method in InputStreamReader class, which then closes the InputStream object.

So, only bReader.close() is sufficient.

Anup Verma
  • 183
  • 1
  • 9
  • 5
    What the source code shows isn't citable as a reference. It's what the *specification* says, in this case the Javadoc, that can be relied on. – user207421 Dec 10 '15 at 04:18
3

Starting from Java 7 you can use try-with-resources Statement

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

Because the BufferedReader instance is declared in a try-with-resource statement, it will be closed regardless of whether the try statement completes normally or abruptly. So you don't need to close it yourself in the finally statement. (This is also the case with nested resource statements)

This is the recomanded way to work with resources, see the documentation for more detailed information

Claudiu Matei
  • 4,091
  • 3
  • 19
  • 33
  • This is nearly identical to @mcdowell's answer from 2009, which also covers some edge-case issues that could occur. – tresf Feb 10 '20 at 18:51
0

You Only Need to close the bufferedReader i.e reader.close() and it will work fine .

Jitendra
  • 52
  • 8
0

I'm late, but:

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
  • 170
  • 2
  • 6
  • Eeeeh that doesn't answer his/her question? She/He asks if it's *necessary* to close FileReader and BufferedReader not an example code. – TornaxO7 Jan 07 '20 at 11:48
  • @TornaxO7 no, it's not an example code. I just wrote part of java source code. So, if you click on some BufferedReader's function with ctrl/cmd key (depends on IDE) you can see BufferedReader's source code, and you can find that fragment of code. So, as you can see BufferedReader just close FileReader by itself ('in' is FileReader in this case, so, when you call bufferReader.close() it calls in.close() inside, exactly in bufferReader.close method) – Dmitry Gashko Jan 07 '20 at 15:12
0

You Don't need to close the wrapped reader/writer.

If you've taken a look at the docs (Reader.close(),Writer.close()), You'll see that in Reader.close() it says:

Closes the stream and releases any system resources associated with it.

Which just says that it "releases any system resources associated with it". Even though it doesn't confirm.. it gives you a nudge to start looking deeper. and if you go to Writer.close() it only states that it closes itself.

In such cases, we refer to OpenJDK to take a look at the source code.

At BufferedWriter Line 265 you'll see out.close(). So it's not closing itself.. It's something else. If you search the class for occurences of "out" you'll notice that in the constructor at Line 87 that out is the writer the class wraps where it calls another constructor and then assigning out parameter to it's own out variable..

So.. What about others? You can see similar code at BufferedReader Line 514, BufferedInputStream Line 468 and InputStreamReader Line 199. Others i don't know but this should be enough to assume that they do.

0

You need to close only the BufferedReader in your scenario.

As others have pointed out, the JavaDocs are ambiguous. Using the try-with-resources block is the best approach when you want close to be called right away, but it doesn't work if you need to keep the reader open (e.g. a class that has a method that returns a stream which uses an underlying reader--it would generally be the caller's responsibility to call close there).

If you don't have access to the source code and want to see whether your reader and JVM calls close on the various readers and streams in your situation, you could override the close method as a simple test.

Path path = Paths.get("/home/example/test.txt");

InputStream fileInputStream = new FileInputStream(path.toFile()) {
    public void close() throws IOException {
        System.out.println("FileInputStream::close()");
        super.close();
    }
};
Reader inputStreamReader = new InputStreamReader(fileInputStream, Charsets.UTF_8) {
    public void close() throws IOException {
        System.out.println("InputStreamReader::close()");
        super.close();
    }
};
BufferedReader bufferedReader = new BufferedReader(inputStreamReader) {
    public void close() throws IOException {
        System.out.println("BufferedReader::close()");
        super.close();
    }
};

bufferedReader.close();

When you run the above, you'll see something very similar to:

BufferedReader::close()
InputStreamReader::close()
FileInputStream::close()

Since there is no explicit specification written in the JavaDoc, we can't be certain of the behavior across all JVMs. However, most of readers/streams seem to follow the above pattern (e.g. you can add a GZIPInputStream to the above example and see that GZIPInputStream::close() also gets called).

jstricker
  • 2,132
  • 1
  • 30
  • 44