Java文件读取必须显式关闭资源以防句柄泄漏,推荐用try-with-resources自动关闭(要求AutoCloseable),否则需在finally中手动关闭并处理close异常,且多层流只需关最外层。

Java 中文件读取出错时,仅靠 catch 块无法自动释放文件句柄——必须显式关闭资源,否则可能引发句柄泄漏。核心原则是:资源获取与释放必须成对出现,且释放逻辑不能依赖异常是否发生。
用 try-with-resources 确保自动关闭
这是最推荐的方式,编译器会自动生成 finally 块调用 close(),无论是否抛异常都会执行:
- 要求资源类型实现
AutoCloseable接口(如FileInputStream、BufferedReader) - 资源在 try 括号内声明,作用域结束即触发
close() - 即使构造资源时就失败(如文件不存在),也不会触发 close(因未成功创建)
示例:
try (FileInputStream fis = new FileInputStream("data.txt");
BufferedReader reader = new BufferedReader(new InputStreamReader(fis))) {
String line = reader.readLine();
// 处理数据
} catch (IOException e) {
// 异常处理,fis 和 reader 已安全关闭
}
手动关闭需放在 finally 块中
若无法使用 try-with-resources(如旧版本 Java 或复杂资源生命周期),必须把 close() 放在 finally 块,并检查非空:
立即学习“Java免费学习笔记(深入)”;
- 避免在 try 块中直接 close(可能因异常跳过)
- 避免在 catch 中 close(可能漏掉其他分支的关闭)
- close() 自身也可能抛 IOException,应单独捕获或忽略(JDK7+ 可用 try-with-resources 替代)
示例:
FileInputStream fis = null;
try {
fis = new FileInputStream("data.txt");
// 读取操作
} catch (IOException e) {
// 处理读取异常
} finally {
if (fis != null) {
try {
fis.close();
} catch (IOException ignored) {
// 关闭失败通常可忽略,或记录日志
}
}
}
不要在 catch 中释放并吞掉所有异常
常见错误是只在 catch 里 close,还把原始异常吃掉:
- 这样会导致上层无法感知真实错误,调试困难
- 资源虽被关闭,但业务逻辑失去异常上下文
- 正确做法:释放资源后重新抛出原异常,或封装后抛出
错误写法:
} catch (IOException e) {
fis.close(); // ❌ 位置错 + 吞异常
}
正确写法(配合 finally)或用 try-with-resources。
注意多层资源嵌套的关闭顺序
当包装流(如 BufferedInputStream 包裹 FileInputStream)时:
- 只需关闭最外层流,它会自动调用内部流的 close()
- 无需也不应手动关闭底层流,否则可能重复关闭或干扰包装逻辑
- try-with-resources 会按声明逆序关闭(先 close 外层,再内层),符合预期
例如:try (BufferedReader r = new BufferedReader(new FileReader("x"))) { ... } —— 只需确保 r 被关闭即可。


















