关闭Java InputStreams


69

我对使用Java InputStreams时close()方法的用法有一些疑问。从大多数开发人员的经验来看,当不再需要InputStream时,应该始终在InputStream上显式调用close()。但是,今天我正在研究使用Java属性文件,并且发现的每个示例都具有以下内容:

Properties props = new Properties();
try {
    props.load(new FileInputStream("message.properties"));
    //omitted.
} catch (Exception ex) {}

在上面的示例中,没有任何方法可以显式调用close(),因为使用InputStream后将无法访问它。我看过InputStreams的许多类似用法,即使它似乎与大多数人所说的显式关闭相矛盾。我通读了Oracle的JavaDocs,它没有提到Properties.load()方法是否关闭InputStream。我想知道这通常是否可以接受,或者是否更喜欢执行以下操作:

Properties props = new Properties();
InputStream fis = new FileInputStream("message.properties");
try {
    props.load(fis);
    //omitted.
} catch (Exception ex) {
    //omitted.
} finally {
    try {
        fis.close();
    } catch (IOException ioex) {
        //omitted.
    }
}

哪种方法更好和/或更有效?还是真的重要吗?


1
感谢大家提供的答案。我希望我能接受所有答案。现在这对我来说很有意义。
杰森·沃特金斯

Answers:


27

属性教程”中的示例在FileInputStream加载后显式关闭了显式窗口,因此我认为可以肯定地认为该load方法不负责任。

// create and load default properties
Properties defaultProps = new Properties();
FileInputStream in = new FileInputStream("defaultProperties");
defaultProps.load(in);
in.close();

仅供参考,我检查了Apache的和谐的执行性能,它也不会在负载关闭流。


属性教程是我所希望的解释。感谢您的链接!
杰森·沃特金斯

49

Properties类将输入流包装在LineReader中以读取属性文件。由于您提供了输入流,因此有责任关闭它。

第二个示例是到目前为止处理流的更好的方法,不要依赖其他人为您关闭流。

您可以做的一项改进是使用IOUtils.closeQuietly()

关闭流,例如:

Properties props = new Properties();
InputStream fis = new FileInputStream("message.properties");
try {
    props.load(fis);
    //omitted.
} catch (Exception ex) {
    //omitted.
} finally {
    IOUtils.closeQuietly(fis);
}

4
请勿在IOUtils 2.6上使用,弃用和删除而无需更换。“请使用try-with-resources语句或手动处理抑制的异常。”
塞尔吉奥

38

我会尝试使用资源(至少对于Java 7+):

Properties props = new Properties();

try(InputStream fis = new FileInputStream("message.properties")) {
    props.load(fis);
    //omitted.
} catch (Exception ex) {
    //omitted.
}

close()退出try块时,应自动调用该调用。


16

如果您使用的是Java 7+,则可以使用以下命令:

try(InputStream is = new FileInputStream("message.properties")) {
    // ...
}

13

它没有在文档中提及props.load会关闭输入流。您应该按照您的建议在finally块中手动关闭输入流。

函数关闭InputStream。使用与非垃圾收集语言中的内存相同的约定:如果可能,打开流的人应该关闭流。否则,很容易让流保持打开状态(您认为某个函数将要关闭它,但实际上并没有关闭……)


+1表示“打开流的人应该关闭流”。如果这不可能,则方法注释应指示调用者这样做。第一个代码示例是不好的做法。
leonbloy

最新的Java 1.6修补程序版本对此有以下注释props.load(Reader)在此方法返回后,指定的流保持打开状态。 在找到此问与答之前,我曾用过TL; DR来寻找文档props.load(Reader),却无法理解为什么我的信息流仍然打开!
kevinarpe

7

看起来第一个代码示例最终依赖于FileInputStream中的finalize方法来实际关闭文件。我想说您的第二个示例更好,即使在两种情况下文件都没有关闭。

在某些情况下,例如Byte流中close不会执行任何操作,可以省略,否则我认为最好在finally块中明确关闭文件。如果打开它,则将其关闭。

Oracle网站上有一本书叫做Java Platform Performance,在其附录中讨论了终结器,它说:

您最好总是自己进行清理,而不要依赖终结器。使用终结器也可能会留下关键资源,这些资源在不确定的时间内无法恢复。如果您正在考虑使用终结器来确保及时释放重要资源,则可能需要重新考虑。


2

让我在其他人的答案中添加一些内容。

如果可以导入Apache Commons IO,则可以使用AutoCloseInputStreams -handy的类:包装您的包装InputStream,然后您使用包装的实例,一旦到达输入结束或当输入结束时,它将自动关闭。该流显式关闭,以先到者为准。


0

因为在`finalize中FileInputStream实现finalize()并调用close()

因此,当不经常使用时,无需关闭 FileInputStream

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.