【问题标题】:Closing Java InputStreams关闭 Java InputStreams
【发布时间】:2011-04-28 20:10:51
【问题描述】:

我对使用 Java InputStreams 时 close() 方法的用法有一些疑问。根据我从大多数开发人员那里看到和读到的内容,您应该始终在不再需要时显式调用 InputStream 上的 close()。但是,今天我正在研究使用 Java 属性文件,我发现的每个示例都有这样的内容:

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

对于上面的例子,没有办法显式调用 close() 因为 InputStream 在使用后是不可访问的。尽管 InputStreams 似乎与大多数人所说的显式关闭相矛盾,但我已经看到了许多类似的 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.
    }
}

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

【问题讨论】:

  • 感谢大家提供的答案。我希望我能接受它们作为答案。现在这对我来说很有意义。

标签: java inputstream


【解决方案1】:

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);
}

【讨论】:

  • 不要在 IOUtils 2.6 上使用,已弃用和删除,无需更换。 "请使用 try-with-resources 语句或手动处理抑制的异常。"
【解决方案2】:

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

Properties props = new Properties();

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

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

【讨论】:

    【解决方案3】:

    Properties Tutorial 中的示例在加载后显式关闭了FileInputStream,所以我认为可以安全地假设load 方法不对它负责,你是。

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

    仅供参考,我检查了PropertiesApache Harmony 实现,它确实没有在加载时关闭流。

    【讨论】:

    • 属性教程是我所希望的解释。感谢您的链接!
    【解决方案4】:

    如果你使用的是 Java 7+,你可以使用这个:

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

    【讨论】:

      【解决方案5】:

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

      函数关闭InputStream 是不正常的。与非垃圾收集语言中的内存相同的约定适用:如果可能,打开流的人应该关闭流。否则,很容易让流保持打开状态(你认为一个函数会关闭它,但它不会,或者其他什么......)

      【讨论】:

      • +1 到“打开流的人应该关闭流” 如果不可能,方法注释应该指示调用者这样做。第一个代码示例是不好的做法。
      • Java 1.6 的最新补丁版本对props.load(Reader) 有这样的评论:此方法返回后,指定的流保持打开状态。 在我找到这个Q&A 之前,我有TL; DR 为 props.load(Reader) 提供了文档,但无法理解为什么我的流仍然打开!
      【解决方案6】:

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

      在某些情况下,例如 Byte 流,close 什么都不做,可以省略,否则我认为最好在 finally 块中显式关闭文件。如果你打开它,你就关闭它。

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

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

      【讨论】:

        【解决方案7】:

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

        如果您可以导入Apache Commons IO,您可以使用非常方便的AutoCloseInputStreams 类:您包装您的InputStream,然后您只需使用您的包装实例,它就会自动关闭已经到达输入的结尾或当流被显式关闭时,以先到者为准。

        【讨论】:

          【解决方案8】:

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

          所以不那么频繁使用的时候,不用关闭FileInputStream

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2011-01-10
            • 1970-01-01
            • 2010-09-27
            相关资源
            最近更新 更多