如何检查一个OutputStream是否已关闭

36

有没有办法在不尝试写入并捕获IOException的情况下检查OutputStream是否关闭?

例如,考虑以下人为的方法:

public boolean isStreamClosed(OutputStream out){
    if( /* stream isn't closed */){
        return true;
    }else{
        return false;
    }
}

你可以用什么代替/* 流没有关闭 */

1
你需要解决的根本问题是什么? - Thorbjørn Ravn Andersen
1
我猜测OP想要避免处理异常的情况。 ;) - Peter Lawrey
这个问题是我在防御性地思考可能会收到什么样的错误输入时产生的,但它更多是一个假设性的问题。此外,“java检查outputstream是否关闭”的谷歌搜索结果中排名最高的是https://dev59.com/Ak3Sa4cB1Zd3GeqPsBSF,但似乎并没有真正回答那个问题。 - chrisbunney
7个回答

38

在尝试向底层流写入数据之前(例如,如果套接字的另一端关闭),可能无法知道底层流是否已关闭。

最简单的方法是使用它并处理它关闭后会发生什么,而不是先进行测试。

无论你测试什么,总有可能会出现IOException,因此你不能避免异常处理代码。添加这个测试可能会使代码变得复杂。


4
这个答案与其他答案的不同之处在于对于没有像 isClosed() 这样的方法进行了解释:_"底层流可能直到尝试将其写入才知道它是否已关闭"_,因此被接受,谢谢 :) - chrisbunney
1
在你调用close()方法关闭连接后,isClosed()方法会返回true。这并不是大多数人希望它做的事情。 ;) - Peter Lawrey

11

很遗憾OutputStream API没有类似于isClosed()的方法。

因此,我只知道一种明确的方法:创建一个名为StatusKnowingOutputStream的类,它包装任何其他输出流并实现其close()方法如下:

public void close() {
    out.close();
    closed = true;
}

现在添加一个名为isClosed()的方法。

public boolean isClosed() {
    return closed;
}

然而,在任何应用程序中都不应该需要这样做。如果您自己的代码关闭了流,则它也应该处理其状态(已关闭/已打开)。但是,如果您从某个第三方库获取流,则该库应该提供一些“boolean canIUseTheStream()”方法。 - bezmax
@bezmax,如果你希望在业务方法中关闭它(你需要将其关闭以便将其发送到其他地方),但你也需要在finally子句中处理它,以便在发生异常时将其关闭,那么处理它的状态可能会更加困难。 - Aritz
这是一个好的想法,但绝对不足以满足通用目的。可能会出现从包装器外部关闭流的情况,例如由操作系统或流提供程序关闭。 - Hypersoft Systems

3
public boolean isStreamClosed(FileOutputStream out){
    try {
        FileChannel fc = out.getChannel();
        return fc.position() >= 0L; // This may throw a ClosedChannelException.
    } catch (java.nio.channels.ClosedChannelException cce) {
        return false;
    } catch (IOException e) {
    }
    return true;
}

只有FileOutputStream才能实现这一点!


2

OutputStream本身不支持这样的方法。 Closable接口的定义方式是,一旦调用close(),就会处理该OutputStream。

也许你应该重新审视一下应用程序的设计,并检查为什么你没有这样做,而导致一个关闭的OutputStream实例仍然在你的应用程序中运行。


1
不可以。如果你自己实现,你可以编写一个isClosed方法,但是如果你不知道具体的类,那么就不行。OutputStream只是一个抽象类。这是它的实现:
   /**
 * Closes this output stream and releases any system resources 
 * associated with this stream. The general contract of <code>close</code> 
 * is that it closes the output stream. A closed stream cannot perform 
 * output operations and cannot be reopened.
 * <p>
 * The <code>close</code> method of <code>OutputStream</code> does nothing.
 *
 * @exception  IOException  if an I/O error occurs.
 */
public void close() throws IOException {
}

OutputStream 不是一个抽象类吗?因此它可以提供一些实现,不是吗? - chrisbunney
是的,抱歉,我的错。但它并没有。 - Kylar
1
是的,很遗憾它没有像@AlexR在他的回答中建议的那样做(https://dev59.com/C2oy5IYBdhLWcg3wScFB#8655939)。 - chrisbunney

1
如果您在测试中进行此操作,请使用Mockito Spys,然后执行verify
我有效地进行了一项测试。
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;

import org.junit.Test;
import java.io.InputStream;

class MyTest {
    @Test
    public void testInputStreamCloseCalled() throws IOException {
        final InputStream spied = spy(...)
    
        // Do something that should call .close() on the spied InputStream
        spied.close()

        verify(spied, times(1)).close();
    }
}

... 是你正在操作的输入流。

也可以与输出流一起使用。


-2

4
这可能适用于System.out PrintStream,实际上也适用于任何PrintStream,但不适用于一般的OutputStreams。 - IceArdor

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接