关闭嵌套的Reader

15

当从文本文件中读取内容时,通常会创建一个 FileReader 并将其嵌套在一个 BufferedReader 中。我应该在完成读取后关闭两个 reader 中的哪一个呢?这有什么区别吗?

FileReader fr = null;
BufferedReader br = null;
try
{
    fr = new FileReader(fileName);
    br = new BufferedReader(fr);
    // ...
}
finally
{
    // should I close fr or br here?
}

当谈到异常安全问题时,我有点偏执。当 BufferedReader 构造函数抛出异常时会发生什么?它会关闭嵌套的读取器吗?还是保证不会抛出异常?

5个回答

10

一般情况下,在最外层的流包装器上调用close()方法会调用被包装的流的close()方法。然而,如果你认为构造函数可能会抛出异常,可以大量使用Closeable接口。

FileReader fr = new FileReader(fileName);
Closeable res = fr;
try {
    BufferedReader br = new BufferedReader(fr);
    res = br;
} finally {
    res.close();
}

因此,即使JVM由于缓冲区的堆空间不足而抛出错误,您也不会泄漏文件句柄。

对于Java 7及以上版本,请使用try-with-resources:

try (FileReader fr = new FileReader(fileName);
    BufferedReader br = new BufferedReader(fr)) {
  // do work
}

如果您正在使用多个可能会抛出异常的包装器(或类似物),这是一个很好的解决方案。当然,您可以查看BufferedReader的文档和代码,以确定构造函数是否真的有任何可能发生异常的机会。 - cthulhu

1

只关闭BufferedReader就足够了,因为它包装了FileReader。如果您查看BufferedReader源代码,您会发现close方法会关闭被包装的流。


0

没有任何保证不会抛出异常。因为缓冲区已经分配,它可能会抛出OutOfMemoryError。我通常将我的代码分成两个部分:获取资源和使用资源。每个部分通常有独特的清理需求。

以下是用来说明的代码:

// Acquire resources section.

final FileReader fr = new FileReader( fileName );

BufferedReader br = null;

try
{
    br = new BufferedReader(fr);
}
finally
{
    if ( br == null )
    {
        // Note that you are closing the fr here
        fr.close( );
    }
}

// Use resources section
try
{
    // ... use br
}
finally
{
    // Now that br is safely constructed, just all its close
    br.close( );
}

我同意你的观点,长时间运行的服务器应用程序中默默丢失文件处理器是最不值得的事情。


0

在 finally 块中关闭 BufferedReader。


0

如果您调用 BufferedReader 的 close 方法,那么 BufferedReader 将会调用 FileReader 的 close 方法。因此,两个 close 方法都会被调用。更确切地说,BufferedReader 不会做任何事情,只会调用 FileReader 的 close 方法。所以这一点并不重要。尽管如此,我认为调用 BufferedReader 的 close 方法也是一个好的实践。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接