【问题标题】:Do I need to close() both FileReader and BufferedReader?我是否需要同时关闭() FileReader 和 BufferedReader?
【发布时间】:2010-11-26 04:37:58
【问题描述】:

我正在使用包裹在 FileReader 周围的 BufferedReader 读取本地文件:

BufferedReader reader = new BufferedReader(new FileReader(fileName));
// read the file
// (error handling snipped)
reader.close();

我是否还需要close() FileReader,或者包装器会处理这个问题? 我见过人们做这样的事情的代码:

FileReader fReader = new FileReader(fileName);
BufferedReader bReader = new BufferedReader(fReader);
// read the file
// (error handling snipped)
bReader.close();
fReader.close();

这个方法是从一个 servlet 调用的,我想确保我没有打开任何句柄。

【问题讨论】:

  • 你知道,您可以阅读源代码以获取此类信息。全部在 JDK 安装目录的 src.zip 中,或者您可以在线阅读,例如 docjar.com/html/api/java/io/BufferedReader.java.html
  • 告诉别人阅读源代码比说“RTFM!”更糟糕。如果源有错误怎么办?隐含地我们想知道正确的行为是什么?
  • 嗯...从这个角度来看:指向 API 规范也好不到哪里去。如果源没有导致其行为不像文档中指定的错误,则您不能依赖文档。所以没有好办法来回答这样的问题。
  • @Atmocreations 下一个维护版本可以愉快地修复一个你依赖的错误,如果你只看源代码。您确实需要知道记录在案的行为是什么。当然,查看源代码并没有错,但你不能假设源代码不会改变。更改记录在案的行为通常比修复错误要更多

标签: java io bufferedreader filereader


【解决方案1】:

没有。

BufferedReader.close()

根据BufferedReaderInputStreamReader 的javadoc 关闭流

还有

FileReader.close()

会。

【讨论】:

  • 除非BufferedReader的构造函数抛出异常。关闭底层流会更干净,尽管您需要注意具有其他资源和缓冲的装饰器。
  • Javadoc 没有说明BufferedReader.close() 是否关闭了底层阅读器。它的描述只是从Reader.close() 复制而来。这可能是实践中的实际行为,但没有记录在案。
  • 如果实际行为不同,那么它应该被记录下来。否则文档是无用的。程序员应该能够认为文档是完整和具体的。
  • 实际文档是否应该更改或不应该更改都没有关系,Reader#close() 的 javadoc 没有说它是否关闭它是包装的 Reader。它所说的与此相关的只是Closes the stream and releases any system resources associated with it.,它不够明确,不能说它关闭或不关闭资源。 “释放资源”也可能会删除 BufferedReader 中对资源的任何引用......这意味着资源没有关闭。
  • 我认为“系统资源”这个术语是明确的,可能有点技术/老式的方式来限定不是由运行时环境(这里是 JVM)而是由底层“系统”管理的资源(也管理JVM的进程)
【解决方案2】:

正如其他人指出的那样,您只需要关闭外包装。

BufferedReader reader = new BufferedReader(new FileReader(fileName));

如果BufferedReader 构造函数抛出异常(例如OutOfMemoryError),这可能会泄漏文件句柄的可能性很小。如果您的应用处于这种状态,那么清理工作需要多么小心可能取决于您不剥夺操作系统可能要分配给其他程序的资源的重要性。

如果包装构造函数在 Java 5 或 6 中可能失败,则可以使用 Closeable 接口:

Reader reader = new FileReader(fileName);
Closeable resource = reader;
try {
  BufferedReader buffered = new BufferedReader(reader);
  resource = buffered;
  // TODO: input
} finally {
  resource.close();
}

Java 7 代码应该使用 try-with-resources 模式:

try (Reader reader = new FileReader(fileName);
    BufferedReader buffered = new BufferedReader(reader)) {
  // TODO: input
}

【讨论】:

  • "Java 7 代码应该使用 try-with-resources 模式"。谢谢,这正是我想要的。这个解决方案是在 09 年编写的,所以 try-with-resources 范式可能应该是新的推荐。此外,它为 OP 提供了比接受和更高投票的答案更好的答案。
  • @tresf 刚刚搜索了 10 分钟试图找到这个答案,我完全同意 - 展示如何打开 Filereader 以便稍后关闭它是关键
【解决方案3】:

BufferedReader的源代码显示关闭BufferedReader时底层关闭。

【讨论】:

  • 我真的很想给这个链接到具体的东西竖起大拇指,但这仅指 OpenJDK 实现,并且由于 JavaDocs 对Reader#close() 不清楚,这并没有提供具体证据表明例如,Oracle JDK 以类似的方式实现。
【解决方案4】:

根据 BufferedReader 来源,在这种情况下 bReader.close 调用 fReader.close 所以技术上你不必调用后者。

【讨论】:

  • 鉴于有说明如何使用它的文档,您应该先查看文档 - 代码中的任何偏差都是错误。
【解决方案5】:

查看源代码后发现示例如下:

FileReader fReader = new FileReader(fileName);
BufferedReader bReader = new BufferedReader(fReader);

BufferedReader 对象上的 close() 方法将调用 Reader 类的抽象 close() 方法,该方法最终将调用 InputStreamReader 中实现的方法b> 类,然后关闭 InputStream 对象。

所以,只有 bReader.close() 就足够了。

【讨论】:

  • 源代码显示的内容不可作为参考引用。这是规范所说的,在这种情况下是Javadoc,可以依赖。
【解决方案6】:

从 Java 7 开始,您可以使用 try-with-resources Statement

try (BufferedReader br = new BufferedReader(new FileReader(path))) {
    return br.readLine();
}

因为BufferedReader实例是在try-with-resource语句中声明的,所以不管try语句是正常完成还是突然完成,它都会被关闭。所以你不需要在finally 语句中自己关闭它。 (嵌套资源语句也是如此)

这是使用资源的推荐方式,请参阅documentation 了解更多详细信息

【讨论】:

  • 这与@mcdowell 2009 年的回答几乎相同,其中还涵盖了可能发生的一些极端情况问题。
【解决方案7】:

您只需要关闭 bufferedReader 即 reader.close() 即可正常工作。

【讨论】:

    【解决方案8】:

    我迟到了,但是:

    BufferReader.java:

    public BufferedReader(Reader in) {
      this(in, defaultCharBufferSize);
    }
    
    (...)
    
    public void close() throws IOException {
        synchronized (lock) {
            if (in == null)
                return;
            try {
                in.close();
            } finally {
                in = null;
                cb = null;
            }
        }
    }
    

    【讨论】:

    • Eeeeh 没有回答他/她的问题?她/他询问是否有必要关闭 FileReader 和 BufferedReader 而不是示例代码。
    • @TornaxO7 不,这不是示例代码。我只是写了部分java源代码。因此,如果您使用 ctrl/cmd 键(取决于 IDE)单击某些 BufferedReader 的功能,您可以看到 BufferedReader 的源代码,并且您可以找到该代码片段。因此,正如您所看到的,BufferedReader 只是自行关闭 FileReader(在这种情况下,'in' 是 FileReader,因此,当您调用 bufferReader.close() 时,它会在内部调用 in.close(),恰好在 bufferReader.close 方法中)跨度>
    【解决方案9】:

    不需要关闭封装的读取器/写入器。

    如果您查看过文档 (Reader.close(),Writer.close()),您会在 Reader.close() 中看到:

    关闭流并释放与之关联的所有系统资源。

    这只是说它“释放与它关联的任何系统资源”。即使它没有确认..它也让你开始更深入地寻找。如果你去Writer.close(),它只会声明它会自行关闭。

    在这种情况下,我们参考OpenJDK查看源代码。

    在 BufferedWriter Line 265 你会看到out.close()。所以它不会自行关闭.. 这是别的东西。如果您在类中搜索“out”的出现,您会注意到在Line 87 的构造函数中,out 是编写器,该类在它调用另一个构造函数的地方包装,然后将out 参数分配给它自己的out 变量..

    那么.. 其他人呢?您可以在BufferedReader Line 514BufferedInputStream Line 468InputStreamReader Line 199 看到类似的代码。其他人我不知道,但这应该足以假设他们这样做了。

    【讨论】:

      【解决方案10】:

      您只需要在您的场景中关闭BufferedReader

      正如其他人指出的那样,JavaDocs 是模棱两可的。当您希望立即调用 close 时,使用 try-with-resources 块是最好的方法,但如果您需要保持阅读器打开(例如,具有返回流的方法的类)它使用底层阅读器——通常调用者有责任在那里调用close)。

      如果您无权访问源代码并想查看您的阅读器和 JVM 是否在您的情况下对各种阅读器和流调用 close,您可以覆盖 close 方法作为一个简单的测试。

      Path path = Paths.get("/home/example/test.txt");
      
      InputStream fileInputStream = new FileInputStream(path.toFile()) {
          public void close() throws IOException {
              System.out.println("FileInputStream::close()");
              super.close();
          }
      };
      Reader inputStreamReader = new InputStreamReader(fileInputStream, Charsets.UTF_8) {
          public void close() throws IOException {
              System.out.println("InputStreamReader::close()");
              super.close();
          }
      };
      BufferedReader bufferedReader = new BufferedReader(inputStreamReader) {
          public void close() throws IOException {
              System.out.println("BufferedReader::close()");
              super.close();
          }
      };
      
      bufferedReader.close();
      

      当您运行上述代码时,您会看到与以下内容非常相似的内容:

      BufferedReader::close()
      InputStreamReader::close()
      FileInputStream::close()
      

      由于 JavaDoc 中没有明确的规范,我们无法确定所有 JVM 的行为。但是,大多数阅读器/流似乎都遵​​循上述模式(例如,您可以在上述示例中添加 GZIPInputStream 并看到 GZIPInputStream::close() 也被调用)。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2014-09-24
        • 2015-08-31
        • 1970-01-01
        • 2018-05-01
        • 2018-07-15
        相关资源
        最近更新 更多