user149408
user149408

Reputation: 5881

Find out whether an InputStream is closed

Does Java have any reliable way of determining whether a java.io.InputStream is closed before I attempt to read from it?

My use case is that I have a method that takes an InputStream argument and reads from it. The method runs in its own thread, and I want to terminate the thread if the input stream is closed.

InputStream implements Closeable, which provides a close() method but apparently no way to query if the instance has already been closed.

Attempting to read from closed InputStream will throw an IOException, but that could have other causes, and there is nothing in the interface contract stating whether this condition is permanent or if, under some circumstances, there is a chance it will go away sometime.

Callers of my method can supply any subclass of InputStream they wish, so relying on specific subclass behavior is not an option.

Any other ideas?

Upvotes: 18

Views: 21866

Answers (3)

Mike Nakis
Mike Nakis

Reputation: 61969

True, an IOException could have other causes besides the InputStream being closed, and true, there is nothing in the interface contract stating whether an error condition is permanent or transient, but: in the vast majority of cases, and certainly in all cases I have ever come across, once an I/O object throws an exception, it is over: there is pretty much nothing else you can do with it other than close it. The only problem that may go away in the future is the availability or not of bytes to read, but when bytes are not available you get "zero bytes read", you do not get an exception.

It is entirely unclear to me what your "function which runs in its own thread" is trying to accomplish, and how it is trying to accomplish it, and why it cannot know whether the InputStream is open or closed. Closing an object places it "past its end-of-life", so doing anything whatsoever with an object once it has been closed is a serious bug, so it should never be possible to get into that situation. This in turn means that the only reason for which you might want to check whether a file is closed or not is to assert that it is closed, never to base conditional logic upon this check. For example, you may want to assert that you did not forget to close the file, or that somebody else did not forget to close it as they were supposed to.

This function will check whether a RandomAccessFile is closed. You can just as easily writeone which works on an InputStream.

private static boolean isClosed( RandomAccessFile randomAccessFile )
{
    try
    {
        randomAccessFile.read();
        return false;
    }
    catch( IOException e )
    {
        /**
         * PEARL: An IOException does not contain any information about the specific kind of I/O error that happened.
         *        So, unless we are willing to parse the message of the exception, (it will be "Stream Closed" or something,) we cannot be
         *        sure whether the exception was thrown due to the file being closed or due to something else.
         */
        return true;
    }
}

Upvotes: 0

erickson
erickson

Reputation: 269657

No. There's no API for determining whether a stream has been closed.

Applications should be (and generally are) designed so it isn't necessary to track the state of a stream explicitly. Streams should be opened and reliably closed in an ARM block, and inside the block, it should be safe to assume that the stream is open. When an an ARM block is used idiomatically, it naturally scopes the reference to a stream so that no one can access it after it's closed.

There are a number of ways that streams can be logically "closed", and many stream implementations will not detect this until a read() call is made. For example, if a server closes a socket, the internal state of the socket object in your client is unlikely to asynchronously reflect this; instead, the next call to read data will detect the closure and update the state. In this example, if the socket was closed cleanly, the read() call would return EOF to signal to the application that all data was safely received. If the connection was terminated abnormally, the call would throw an exception to indicate some data may have been lost.

It is reasonable to assume that a stream that has thrown an IOException is dead, and further attempts to read from it will continue to fail. If you could have detected this condition before making the call to read(), you'd presumably still handle it in the same way.

The exception to this approach is that some streams support a read timeout, where an exception is raised if no input is received for some time, but the stream remains valid. It would only make sense for a caller to pass such a stream to a method that explicitly supports retrying reads.

Upvotes: 15

Jose Romero
Jose Romero

Reputation: 569

I think the cleanest way to do this is add a custom class which extends any sort of InputStream that you want to use. Add it to your utils package or something. And have in that class a value called:

private boolean isClosed = false;

So when you call close you can do something like:

@Override
public void close() throws IOException {
    if(!isClosed){
        super.close();
        isClosed = true;
    }
}

public boolean isClosed() {
    return isClosed;
} 

It'd be the cleanest way for your specific requirement in my opinion. Also you can manage the error in a way that you can return a specific custom error on different scenarios.

Upvotes: 1

Related Questions