Reputation: 3850
I am studying a Java code example about reading file using input stream. I observed that there are 3 input streams initialized in the order of fis
, bis
, and dis
(typed FileInputStream
, BufferedInputStream
, and DataInputStream
correspondingly), with dependency fis<--(depends-on)--bis<--(depends-on)--dis. I also observed that they are closed in the same order: fis
, bis
, then dis
.
My question is: shouldn't them be closed in REVERSE order? i.e. the latestly initialized shall be closed first?
Here is the code example. I also pasted it here:
public class BufferedInputStreamExample {
public static void main(String[] args) {
File file = new File("C:\\testing.txt");
FileInputStream fis = null;
BufferedInputStream bis = null;
DataInputStream dis = null;
try {
fis = new FileInputStream(file);
bis = new BufferedInputStream(fis);
dis = new DataInputStream(bis);
while (dis.available() != 0) {
System.out.println(dis.readLine());
}
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
fis.close();
bis.close();
dis.close();
} catch (IOException ex) {
ex.printStackTrace();
}
}
}
}
Upvotes: 0
Views: 2410
Reputation: 50021
The normal thing to do is to only close the outermost stream. DataInputStream
and BufferedInputStream
are both types of FilterInputStream
, whose close
method specifies that it calls the close method of the underlying stream. So you do not need to explicitly close the others or even maintain a reference to them in a variable. For example it is fine to initialize dis
as:
dis = new DataInputStream(
new BufferedInputStream(
new FileInputStream(file)));
In practice, assuming the classes are implemented properly according to the spec, it does not matter whether you close any 1, any 2, or all 3 of the streams, in any order, or any number of times, because:
InputStream
and OutputStream
implement the Closeable
interface, whose close
method states "If the stream is already closed then invoking this method has no effect.")FileInputStream
actually needs to be closed, since it is the only one which holds open a real filesystem resource and therefore is the only stream which has visible side effects if held open (e.g., you cannot delete the file). The BufferedInputStream
and DataInputStream
are ordinary objects, which can be garbage collected in the ordinary way, whether closed or not. The FileInputStream
will also be closed when garbage collected if you forgot to do it, but it's prudent to do it as soon as possible, since there are no guarantees about when garbage collection occurs.So the example you posted is over-engineered, but not dangerous.
In modern Java (7+) the far more elegant way to ensure the closure of everything in your example, rather than using a finally
block, is to use the try-with-resources statement, which lets you declare the streams, open them, and guarantee their closure, in one go:
try (DataInputStream dis = new DataInputStream(
new BufferedInputStream(
new FileInputStream(file)))) {
while (dis.available() != 0) {
System.out.println(dis.readLine());
}
} catch (IOException e) {
e.printStackTrace();
}
Upvotes: 3
Reputation: 362
While the docs are not 100% clear, it looks like closing the DataInputStream
should be sufficient.
Both DataInputStream
and BufferedInputStream
are subclasses of FilterInputStream
, and here is its documentation of close()
(Java 7 SE):
Closes this input stream and releases any system resources associated with the stream. This method simply performs in.close().
Here in
is the wrapped stream.
Assuming neither class overrides the behaviour of the superclass, closing the DataInputStream
will recursively close all the wrapped streams.
Upvotes: 1
Reputation: 201419
I would suggest in the reverse of the order they are opened (so dis
, bis
then fis
), but such isn't required (just style) or better yet - try-with-resources
like
File file = new File("C:\\testing.txt");
try (FileInputStream fis = new FileInputStream(file);
BufferedInputStream bis = new BufferedInputStream(fis);
DataInputStream dis = new DataInputStream(bis)) {
while (dis.available() != 0) {
System.out.println(dis.readLine());
}
} catch (IOException e) {
e.printStackTrace();
}
Upvotes: 2
Reputation: 968
You could use try-with-resources and not worry about the order of closing
public class BufferedInputStreamExample {
public static void main(String[] args) {
File file = new File("C:\\testing.txt");
try(FileInputStream fis = new FileInputStream(file);
BufferedInputStream bis = new BufferedInputStream(fis);
DataInputStream dis = new DataInputStream(bis)) {
while (dis.available() != 0) {
System.out.println(dis.readLine());
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
Upvotes: 2
Reputation: 1903
you only need to close the outer object (DataInputStream). it will close all the objects it depends on.
Upvotes: 2