不关闭已结束的InputStream有什么意义?

5

InputStream 实现 Closeable 接口。

我明白,关闭尚未结束的 InputStream 可以释放一些底层资源,并且保持其开启状态可以使其他方法继续从中读取。

但是, 已经结束了的 InputStream 不关闭会有什么意义呢?
如果没有意义,为什么到达 InpuntStream 的结尾并不意味着要关闭它呢?

同样的问题也适用于 Reader

8个回答

10

mark()reset() 允许您在一些接口的实现中“回到”之前的位置。

这在实现解析器和匹配正则表达式时非常有用,因为通常需要进行向前查看


我的问题是关于InputStream(和Reader),而不是一般的Closeable。我不知道有可倒带的InputStream或Reader。 - java.is.for.desktop
啊,好的,这是关于标记和重置的问题,我忘记它们是InputStream / Reader的方法了。 - java.is.for.desktop
所以,这确实是一个非常有道理的好理由。 - java.is.for.desktop
是的。我一直以为InputStream是一个接口而不是一个抽象类。 - gpeche
我不是100%确定,但是合理地期望FileInputStream、ByteArrayInputStream和StringReader支持mark()和reset()。 - gpeche

4

针对您对org.life.java的评论,我的回答是:

我知道,问题是:为什么InputStream的结束不意味着close()?

因为对于某些流来说,您可以倒回并重新开始读取。对于其他一些流,例如套接字,这是不可能的,但它们必须遵守合同规则。

此外,这就是关闭流的正确方式(未显示异常处理):

InputStream stream = openMethod( );

try
{
   consumeMethod( stream );
}
finally
{
   stream.close( );
}

换句话说,无论您是否完全使用了流,都应该释放已获取的资源。

你的意思是,InputStreamReader有子类可以倒带吗? - java.is.for.desktop
1
@java.is.for.desktop。是的,如果markSupported返回true,则可以使用markreset流位置。gpeche在他的答案中提到了这一点。 - Alexander Pogrebnyak

3

在Windows下的一个原因是为了保持文件锁定。打开的文件无法被重命名、删除或移动。


这个原因很有道理!可悲的是,它在Javadoc中没有记录。 - java.is.for.desktop
1
这是平台相关的行为。除非你确切知道自己在做什么,否则不要做这样的事情,因为这种范例会在Unix平台上出现问题。 - Thorbjørn Ravn Andersen
1
由于它是特定于平台的(仅在Windows上有效),因此不应该在Javadoc中记录。 - Thilo

1

在编程中有一个微妙的用例,即在输入流结束后不关闭它:包装流。默认情况下,关闭包装器(如FilterInputStream)将关闭底层流。有时您想停止使用包装器但继续使用底层流,因此您必须仅丢弃包装器而不调用close。

考虑以下示例:

try (InputStream in0 = new FileInputStream(...)) {
    int len = (...);
    // Hypothetical class `BoundedInputStream`
    InputStream in1 = new BoundedInputStream(in0, len);
    while (in1.read() != -1);  // Discard bytes until end
    // Now stop using in1 without calling close(),
    // because in1.close() would trigger in0.close()
    
    // Read more data in a different way
    DataInput in2 = new DataInputStream(in0);
    long x = in1.readLong();  // Reads exactly 8 bytes
    // We can neglect in2 without calling close() because
    // itself doesn't hold any limited resources like file handles
    
    // Read more data in a different way
    CheckedInputStream in3 = new CheckedInputStream(in0);
    (...)
    
    // Ultimately call in0.close() directly
}

1

您可以使用mark()reset()方法标记和重置InputStream。因此,一旦到达数据的末尾,您仍然可以返回到标记的位置。想要reset() InputStream的人可能不希望在结束时关闭它。


0

我不了解java中与InputStream相关的语义,但一般来说,您可能不会关闭流,因为您没有自己打开它,只是在其上工作,并依赖调用方(另一个方法)来关闭流。如果您自己打开了流,则应始终将其关闭。


好的,但是Java API没有在结束后关闭InputStream的原因是什么?(这意味着在结束时关闭,据我所知并不会有太大的问题) - java.is.for.desktop

0

隐式关闭不是很好,因为

  • 只有在流到达其结尾时才会执行,这并不总是情况(在途中可能会发生一些异常,或者您只读取文件的前几个字节),因此您仍然需要处理这些其他情况。拥有一个几乎总是有效的隐式关闭会让人们更加忘记他们的finally块。
  • 某些流可以倒回(标记/重置)。

0
从InputStream的API来看,特定实现在流结束时关闭是没有问题的。这对于许多流来说可能是一个非常好的主意。

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