【问题标题】:Is it safe to use Apache commons-io IOUtils.closeQuietly?使用 Apache commons-io IOUtils.closeQuietly 安全吗?
【发布时间】:2013-01-04 09:05:18
【问题描述】:

这是代码吗

    BufferedWriter bw = new BufferedWriter(new FileWriter("test.txt"));
    try {
        bw.write("test");
    } finally {
        IOUtils.closeQuietly(bw);
    }

安全与否?据我了解,当我们关闭 BufferedWriter 时,它会将其缓冲区刷新到底层流,并且可能由于错误而失败。但是 IOUtils.closeQuietly API 说任何异常都会被忽略。

是否有可能由于 IOUtils.closeQuietly 而导致数据丢失被忽视?

【问题讨论】:

  • 不是答案,但try-with-resources 声明将消除大多数使用IOUtils.closeQuietly 的需求。
  • 不错的答案,但这个功能是 Java 7 中的新功能。如果您由于某种原因(例如较旧的 Android 版本)无法使用 Java 6,那么closeQuietly() 仍然是可行的方法。跨度>
  • IOUtils.closeQuietly 已被弃用,现在使用 try with resource 代替。
  • closeQuietly(..) 如果资源的 close() 方法抛出检查异常,仍然是必需的。在这种情况下,try-with-resources 不能用作 close() 上的异常会冒泡。

标签: java apache-commons apache-commons-io


【解决方案1】:

关于closeQuietly()的javadoc的代码应该是这样的:

BufferedWriter bw = null;

try {
    bw = new BufferedWriter(new FileWriter("test.txt"));
    bw.write("test");
    bw.flush(); // you can omit this if you don't care about errors while flushing
    bw.close(); // you can omit this if you don't care about errors while closing
} catch (IOException e) {
    // error handling (e.g. on flushing)
} finally {
    IOUtils.closeQuietly(bw);
}

closeQuietly() 不适用于一般用途,而不是直接在 Closable 上调用 close()。它的预期用例是确保在 finally 块内关闭 - 您必须在此之前完成所有错误处理。

这意味着,如果您想在调用close()flush() 期间对异常做出反应,那么您必须以正常方式处理它。在 finally 块中添加 closeQuietly() 只是确保关闭,例如当刷新失败并且在 try-block 中没有调用 close 时。

【讨论】:

  • 我认为 bw.flush() 是不必要的,bw.close() 无论如何都会调用flush()
  • @EvgeniyDorofeev 是的,只要你把 close() 留在里面。但是当你只关心刷新期间的异常而不关心关闭时,你需要在这里显式地刷新。刚刚编写了两个方法调用以使示例更加通用。
  • 要明确一点:您可以省略对bw.close() 的调用,并且 bw 仍将在 finally{} 子句中正确关闭。这样做还可以让您了解bw.close() 期间的任何错误
  • close() 并不总是调用flush(),有时close() 调用flush,但其中隐藏了IOException。例如,请参阅FilterOutputStream
【解决方案2】:

只要您的应用程序不关心写入是否成功且没有错误,它就是安全的。如果您的应用程序需要处理写入错误,这是不安全的,因为buffered data flushed on close 可能会丢失并且错误被吞没。

【讨论】:

    【解决方案3】:

    是的,使用它是安全的,但仅适用于 Java6 及更低版本。在 Java7 中,您应该使用 try-with-resource

    它将消除您拥有的大部分样板代码以及使用IOUtils.closeQuietly 的需要。

    现在,你的例子:

        BufferedWriter bw = new BufferedWriter(new FileWriter("test.txt"));
        try {
            bw.write("test");
        } finally {
            IOUtils.closeQuietly(bw);
        }
    

    可以写成:

       try (BufferedWriter bw = new BufferedWriter(new FileWriter("test.txt"))) {
           bw.write("test");
       }
    

    请务必注意,为了使用 try-with-resource 方法,您的资源需要实现 Java 7 中引入的名为 java.lang.AutoCloseable 的新接口。

    此外,您可以在 try-with-resource 块中包含许多资源,只需用 ; 分隔它们

       try (
           BufferedWriter bw1 = new BufferedWriter(new FileWriter("test1.txt"));
           BufferedWriter bw2 = new BufferedWriter(new FileWriter("test2.txt"))
       ) {
           // Do something useful with those 2 buffers!
       }   // bw1 and bw2 will be closed in any case
    

    【讨论】:

      【解决方案4】:

      理论上这是可能的,但我不能说我见过 close() 失败。通常fail fast意味着之前的IO操作比如打开文件会先失败。您可以编写一个不忽略 IOExceptions 的关闭函数,但如果它是 try/catch 块中的某些内容失败,这可能会破坏异常的真正原因。

      你想要的是类似下面的东西(在大多数情况下这是矫枉过正的)

      try {
          // write to bw.
          bw.close(); // throw IOException if an error occurs.
      
      } finally {
          // don't clobber a previous IOException
          IOUtils.closeQuietly(bw);
      }
      

      【讨论】:

      • 您使用不正确 - IOUtils.closeQuietly() 不适合一般用途,而不是直接在 Closable 上调用 close()。它的预期用例是确保在 finally 块内调用 close() 以避免资源泄漏 - 所有错误处理(日志记录、异常包装和重新抛出)都应该在此之前完成 - 请参阅 Fabian 的答案
      • @JarekPrzygódzki 您最后一次看到关闭时出现 IOException 是什么时候?
      • 这种情况很少见,但确实会发生 - 你永远不知道 Closeable 或 {Input, Output}Stream 背后的内容。并且静默异常几乎从来都不是好事。
      • 我检查了source code 并阅读了文档。 closeQuietly() 只不过是对 close() 的调用,被忽略异常的 try/catch 包围。文档同意。您可以使用closeQuietly() 代替close(),finally{ } 块是执行此操作的理想位置。
      猜你喜欢
      • 2013-06-25
      • 1970-01-01
      • 2018-06-23
      • 1970-01-01
      • 2011-09-24
      • 2019-05-20
      • 1970-01-01
      • 1970-01-01
      • 2012-04-07
      相关资源
      最近更新 更多