关闭缓冲流时自动关闭底层物理流,靠的是装饰者模式和 close() 方法的链式调用设计;只需关闭最外层流,内部会依次调用被包装流的 close(),多层嵌套也只需关最上层,用 try-with-resources 最安全。

关闭缓冲流时自动关闭底层物理流,靠的是 Java IO 的装饰者模式和 close() 方法的链式调用设计。你不需要、也不应该手动再关一次底层流——那样反而容易出错。
装饰者模式决定了关闭行为
缓冲流(如 BufferedInputStream、BufferedReader)不是独立工作的流,而是对已有流(如 FileInputStream、FileReader)的“包装”。这种包装关系在构造时就建立:
- BufferedInputStream bis = new BufferedInputStream(new FileInputStream("a.txt"));
- BufferedReader br = new BufferedReader(new FileReader("b.txt"));
此时,bis 和 br 内部持有对底层流的引用,并在其 close() 方法中主动调用被包装流的 close() ——这是 JDK 源码里明确实现的逻辑,不是约定,是强制行为。
只需关闭最外层流,其他会自动释放
调用 bis.close() 或 br.close() 时,实际发生的是:
- 先执行自身清理(比如清空缓冲区、调用 flush())
- 再调用内部持有的底层流的 close()
- 底层流再继续向它自己的包装者或原始数据源传递关闭动作(如果还有)
所以,哪怕你套了多层(比如 BufferedReader → InputStreamReader → FileInputStream),也只关最上面那个即可。
用 try-with-resources 最安全省心
JDK 7+ 推荐用 try-with-resources,它会在离开作用域时自动按声明逆序调用 close(),且已内置对装饰链的支持:
try (BufferedReader br = new BufferedReader(
new InputStreamReader(
new FileInputStream("data.txt"), "UTF-8"))) {
String line;
while ((line = br.readLine()) != null) {
System.out.println(line);
}
} // ← 这里 br.close() 被自动调用,底层流全释放
即使中间某层抛异常,JVM 仍会确保所有已成功初始化的资源都被关闭。
千万别反向关闭或重复关闭
以下写法是错误的:
- 先关 FileInputStream,再关 BufferedInputStream → 底层流已关,上层再调 read() 或 close() 会抛 IOException: Stream closed
- 两层都显式调 close() → 可能触发重复关闭,某些流实现会报错或静默失败
只要最外层流关了,整个链就断开了,系统资源(文件句柄、内存缓冲区等)都会被回收。










