
本文详解因未正确关闭 filereader 导致 json 文件被锁定、进而无法删除的问题,并提供基于 try-with-resources 的安全读取与资源释放方案。
在使用 Apache POI 将 JSON 数据转换为 Excel 文件的自动化流程中,一个常见却容易被忽视的问题是:JSON 文件写入后无法被删除,抛出异常:
java.nio.file.FileSystemException: .\Json_files\db-AAPL.json: The process cannot access the file because it is being used by another process
该异常的根本原因并非 Windows 系统独占或杀毒软件干扰,而是 Java 代码中 FileReader 资源未显式关闭,导致文件句柄(file handle)持续被占用,操作系统因此拒绝删除操作。
回顾原始代码中的关键片段:
Object obj = parser.parse(new FileReader(".//Json_files//db-" + stockname + ".json"));此处 new FileReader(...) 创建了一个未受管理的流对象,JSONParser.parse() 内部虽可能读取完毕,但 不会自动关闭传入的 Reader —— 这是许多第三方解析库(如 org.json.simple)的设计约定。因此,文件流长期处于打开状态,直至 JVM 垃圾回收(甚至不保证及时回收),造成后续 Files.deleteIfExists() 失败。
立即学习“Java免费学习笔记(深入)”;
✅ 正确做法:使用 try-with-resources 语句确保 FileReader 在作用域结束时自动、可靠关闭:
JSONParser parser = new JSONParser();
Object obj;
try (FileReader reader = new FileReader(".//Json_files//db-" + stockname + ".json")) {
obj = parser.parse(reader); // 解析完成后 reader 自动关闭
} catch (IOException | ParseException e) {
throw new RuntimeException("Failed to parse JSON file: " + stockname, e);
}⚠️ 同时,请检查其他潜在资源泄漏点:
- PrintWriter out 已正确调用 out.close() ✅
- FileOutputStream fo 已调用 fo.close() ✅
- 但全局静态字段 public static FileInputStream fi; 在代码中从未被初始化或使用,属于冗余声明,建议直接移除,避免误导和潜在资源误用风险。
? 补充最佳实践建议:
- 避免静态文件流对象:wb, s, fo 等不应声明为 static,否则多线程/多轮执行时易引发状态污染与资源竞争;
- Excel 写入后立即关闭工作簿:当前代码中 wb.write(fo) 后未调用 wb.close(),虽 XSSFWorkbook 在 write() 时已刷新内容,但显式关闭可释放内部资源(如临时 ZIP 条目);
- 统一路径处理:使用 Paths.get(...).toAbsolutePath() 替代硬编码相对路径(如 ".//Json_files//..."),提升可移植性与调试可见性;
- 增强删除逻辑健壮性:在 deleteIfExists() 后添加存在性校验,或捕获 FileSystemException 并记录具体原因:
Path jsonPath = Paths.get(".//Json_files//db-" + stockname + ".json");
if (Files.exists(jsonPath)) {
try {
Files.delete(jsonPath);
System.out.println("Deleted JSON file: " + jsonPath);
} catch (IOException e) {
System.err.println("Failed to delete " + jsonPath + ": " + e.getMessage());
}
}通过以上重构,不仅能彻底解决“文件被占用”异常,还能显著提升代码的健壮性、可维护性与资源安全性。记住:所有实现了 AutoCloseable 的资源(FileReader, FileInputStream, FileOutputStream, Workbook 等),都应优先通过 try-with-resources 管理生命周期。










