Zilk
Zilk

Reputation: 9285

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

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.

Upvotes: 216

Views: 209343

Answers (10)

jstricker
jstricker

Reputation: 2180

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).

Upvotes: 0

Omar Abdul'Azeez
Omar Abdul'Azeez

Reputation: 173

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.

Upvotes: 1

Dmitry Gashko
Dmitry Gashko

Reputation: 300

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

Upvotes: 0

Claudiu Matei
Claudiu Matei

Reputation: 4101

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

Upvotes: 3

Anup Verma
Anup Verma

Reputation: 183

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.

Upvotes: 7

Jitendra
Jitendra

Reputation: 52

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

Upvotes: 0

Atmocreations
Atmocreations

Reputation: 10071

no.

BufferedReader.close()

closes the stream according to javadoc for BufferedReader and InputStreamReader

as well as

FileReader.close()

does.

Upvotes: 220

McDowell
McDowell

Reputation: 108969

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
}

Upvotes: 113

Brian Agnew
Brian Agnew

Reputation: 272417

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

Upvotes: 7

Csaba_H
Csaba_H

Reputation: 8245

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

Upvotes: 7

Related Questions