Do I need to close() both FileReader and BufferedReader?
Asked Answered
B

10

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.

Berry answered 7/9, 2009 at 10:15 Comment(4)
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 docjar.com/html/api/java/io/BufferedReader.java.htmlHeiner
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?Puerilism
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.Monotheism
@Monotheism 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.Sulphonate
M
220

no.

BufferedReader.close()

closes the stream according to javadoc for BufferedReader and InputStreamReader

as well as

FileReader.close()

does.

Monotheism answered 7/9, 2009 at 10:20 Comment(6)
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.Underplay
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.Tertias
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.Monotheism
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.Cabob
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)Recapitulate
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 docs.oracle.com/javase/tutorial/essential/exceptions/…Tula
S
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
}
Swanner answered 7/9, 2009 at 10:57 Comment(2)
"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.Winthorpe
@Winthorpe 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 keyCordate
W
7

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

Welkin answered 7/9, 2009 at 10:19 Comment(1)
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.Offenbach
M
7

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

Mosqueda answered 7/9, 2009 at 10:20 Comment(1)
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.Cabob
F
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.

Flynn answered 2/9, 2015 at 18:0 Comment(1)
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.Sadiras
R
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

Ranchman answered 3/8, 2018 at 8:12 Comment(1)
This is nearly identical to @mcdowell's answer from 2009, which also covers some edge-case issues that could occur.Winthorpe
T
1

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.

Tureen answered 2/5, 2019 at 10:8 Comment(0)
L
0

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

Leucocyte answered 12/2, 2015 at 20:49 Comment(0)
P
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;
        }
    }
}
Perversion answered 7/12, 2018 at 19:56 Comment(2)
Eeeeh that doesn't answer his/her question? She/He asks if it's necessary to close FileReader and BufferedReader not an example code.Amongst
@Amongst 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)Perversion
M
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).

Monoacid answered 11/10, 2021 at 15:1 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.