modeller
modeller

Reputation: 3850

What is the correct order to close input streams?

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

Answers (5)

Boann
Boann

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:

  1. As said, closing an outer stream closes the inner stream.
  2. Closing an already closed stream harmlessly does nothing. (InputStream and OutputStream implement the Closeable interface, whose close method states "If the stream is already closed then invoking this method has no effect.")
  3. Only the 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

Leandro Galvan
Leandro Galvan

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

Elliott Frisch
Elliott Frisch

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

blr
blr

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

Roberto Attias
Roberto Attias

Reputation: 1903

you only need to close the outer object (DataInputStream). it will close all the objects it depends on.

Upvotes: 2

Related Questions