
本文详解因未正确关闭filereader导致json文件被锁定、无法删除的常见问题,提供基于try-with-resources的安全读取方案,并附完整修复代码与最佳实践建议。
在使用Apache POI将JSON数据写入Excel后尝试删除原始JSON文件时,抛出 java.nio.file.FileSystemException: The process cannot access the file because it is being used by another process 异常,根本原因在于:JSONParser.parse() 中直接传入 new FileReader(...) 实例,但该流未显式关闭,导致文件句柄长期被JVM持有,操作系统禁止删除正在被读取的文件。
? 问题定位:未关闭的 FileReader 是罪魁祸首
观察原代码关键行:
Object obj = parser.parse(new FileReader(".//Json_files//db-" + stockname + ".json"));此处 FileReader 是匿名创建且无任何 close() 调用,即使后续 JSONParser 内部完成解析,JVM 也不会自动释放底层文件句柄(尤其在 Windows 系统中表现明显)。这使得 Files.deleteIfExists(...) 始终失败。
✅ 正确解法:使用 try-with-resources 自动管理资源
Java 7+ 推荐使用 try-with-resources 语句确保 Reader 在作用域结束时自动关闭,无论是否发生异常:
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);
}✅ 优势:语法简洁、异常安全、100% 保证资源释放。
? 完整修复建议(整合到原逻辑中)
替换原 for 循环内 JSON 解析部分如下(含异常处理与资源清理):
// ... 上方已有 PrintWriter 写入 JSON 文件的逻辑(已正确 close())
// ✅ 安全读取并解析 JSON(自动关闭 FileReader)
JSONParser parser = new JSONParser();
Object obj;
try (FileReader reader = new FileReader(".//Json_files//db-" + stockname + ".json")) {
obj = parser.parse(reader);
} catch (IOException | ParseException e) {
throw new RuntimeException("Failed to parse JSON for stock: " + stockname, e);
}
JSONObject jsonObj = (JSONObject) obj;
JSONObject response = (JSONObject) jsonObj.get("response");
JSONObject arraybody = (JSONObject) response.get("data");
JSONArray arrayindex = (JSONArray) arraybody.get("arrayRowData");
// ... 后续 Excel 构建逻辑保持不变(s.createSheet, s.createRow 等)
// ✅ Excel 输出后,确保 FileOutputStream 已关闭(原代码已做,但建议增强)
fo = new FileOutputStream(dir + "//DB_Search" + "-" + formatedate + ".xlsx");
wb.write(fo);
fo.flush();
fo.close(); // ✅ 正确
// ✅ 此时 JSON 文件已无任何打开句柄,可安全删除
Path jsonPath = Paths.get(".//Json_files//db-" + stockname + ".json");
if (Files.exists(jsonPath)) {
Files.delete(jsonPath); // 或 Files.deleteIfExists(jsonPath)
System.out.println("Deleted JSON file: " + jsonPath);
}⚠️ 额外注意事项
- 避免静态流对象污染:当前代码中 public static FileInputStream fi; 和 public static FileOutputStream fo; 声明为 static 是危险的——多线程或多次执行时易引发资源冲突与内存泄漏。✅ 应改为局部变量(如示例中 fo 的用法),并在使用后立即关闭。
- 路径健壮性:建议统一使用 Paths.get(...).toAbsolutePath() 处理相对路径,避免因工作目录变化导致文件定位失败。
- 异常日志化:生产环境应使用 SLF4J/Log4j 记录删除失败详情,而非仅 System.out.println。
- 批量操作优化:若需处理大量股票,可考虑在循环外统一收集待删文件路径,最后批量删除,提升 I/O 效率。
✅ 总结
文件删除失败的本质是资源泄漏,而非权限或路径错误。只要确保所有 InputStream / Reader / OutputStream / Writer 类型资源均通过 try-with-resources 或显式 close() 释放,即可彻底规避“文件被占用”异常。本方案不仅修复当前问题,更符合 Java 资源管理最佳实践,显著提升代码健壮性与可维护性。










