209

我正在使用包裹在 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 调用的,我想确保我没有打开任何句柄。

4

10 回答 10

216

不。

BufferedReader.close()

根据BufferedReaderInputStreamReader的 javadoc关闭流

FileReader.close()

做。

于 2009-09-07T10:20:10.323 回答
112

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

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
}
于 2009-09-07T10:57:08.317 回答
7

BufferedReader的源代码显示,当您关闭 BufferedReader 时,底层已关闭。

于 2009-09-07T10:20:11.310 回答
6

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

于 2009-09-07T10:19:57.533 回答
6

检查源代码后,我发现示例:

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

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

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

于 2015-09-02T18:00:08.940 回答
3

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

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

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

这是使用资源的推荐方式,有关更多详细信息,请参阅文档

于 2018-08-03T08:12:28.343 回答
0

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

于 2015-02-12T20:49:46.063 回答
0

我迟到了,但是:

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;
        }
    }
}
于 2018-12-07T19:56:14.317 回答
0

不需要关闭包装的阅读器/作者。

如果您查看了文档 ( Reader.close(), Writer.close()),您会看到Reader.close()其中说:

关闭流并释放与其关联的任何系统资源。

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

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

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

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

于 2019-05-02T10:08:39.657 回答
0

您只需要BufferedReader在您的方案中关闭。

正如其他人指出的那样,JavaDocs是模棱两可的。当您想立即被调用时,使用 try-with-resources 块是最好的方法close,但如果您需要保持阅读器打开(例如,具有返回使用潜在的读者——通常是调用者的责任在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在上述示例中添加 a 并看到它GZIPInputStream::close()也被调用)。

于 2021-10-11T15:01:41.817 回答