简体   繁体   中英

Does closing InputStream close the Channel associated with it?

If I create a Channel from an InputStream , and then close the InputStream , will it close the associated Channel ? Do I need to close the associated Channel explicitly? I know closing Channel will close Stream, but what about the reverse?

try (InputStream ioStream = getInputStream()) {
    ReadableByteChannel inputChannel = Channels.newChannel(ioStream);
    //do something
} 

In the general case, the InputStream knows nothing about the Channel , so closing the InputStream cannot automatically close the Channel .

However, trying to read from the Channel after the InputStream has been closed will throw an IOException :

  • the channel has to fetch data from the inputstream through InputStream.getBytes()
  • InputStream.getBytes() will throw an IOException if the inputstream has been closed.

For the special case of a FileInputStream the Channels.newChannel(ioStream) call will return FileInputStream.getChannel() , so in this special case closing the inputstream will also close the channel.

I assume the core of your concern is that you don't have a "leak" by leaving resources open.

As far as I'm aware, so long as the underlying resource gets closed you won't have a leak since that underlying object (with native methods) is what's talking to the OS and keeping the resource open.

Since the documentation says that it simply redirects to the stream (emphasized in bold by me) then closing the InputStream itself will close the only actual resource as Channel.newChannel(InputStream) is not creating a new resource.

I would, however, rather open your Channel in a try-with-resources and let it be closed automatically, which will cascade to the underlying resource.

User Slaw has the correct idea that the InputStream has no knowledge of the Channel (except in the special case of a FileInputStream as shown by Alex). This is one of the reasons you should close your wrapper resources rather than just the underlying resources, so that your wrappers have consistent knowledge of the actual resource.


java.nio.channels.Channels.newChannel(InputStream) - Java 1.8 API

Constructs a channel that reads bytes from the given stream .

The resulting channel will not be buffered; it will simply redirect its I/O operations to the given stream . Closing the channel will in turn cause the stream to be closed.

Parameters:
in - The stream from which bytes are to be read

Returns:
A new readable byte channel

Looking at the implementation of Channels.newChannel:

    public static ReadableByteChannel newChannel(InputStream in) {
        Objects.requireNonNull(in, "in");

        if (in.getClass() == FileInputStream.class) {
            return ((FileInputStream) in).getChannel();
        }

        return new ReadableByteChannelImpl(in);
    }

As you can see, if the input stream is a file stream we have a special case. In this special case the close() method of the resulting channel will just return ! checked ! checked , where checked is a private boolean field of the corresponding file input stream. When you close the file input stream it sets the closed to true and then the channel will also think that it's closed:

   InputStream is = new FileInputStream(new File("test.file"));
   ReadableByteChannel channel = Channels.newChannel(is);
   System.out.println(channel.isOpen());  // True
   is.close();
   System.out.println(channel.isOpen());  // False

However, this is an implementation detail, so you can't rely on it. Also, if the input stream is not a file input stream, then the above will not work at all.

From Java API 7:

The resulting channel will not be buffered; it will simply redirect its I/O operations to the given stream. Closing the channel will in turn cause the stream to be closed .

Hope it helps!

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM