FileStream莫名关闭:NPOI读取文件抛出“无法访问已关闭文件”异常
解决NPOI读取文件时抛出“Cannot access a closed file”异常的问题
可能的根因
- 文件复制未完全落地:调用
File.Copy后,系统可能因磁盘缓存机制未立即完成数据写入,此时读取文件易触发流异常。 - 外部进程干扰:杀毒软件、系统索引服务或其他后台进程可能锁定/修改目标文件,导致当前读取流被强制关闭。
- 流重复使用问题:同一个
FileStream先后传入XSSFWorkbook和HSSFWorkbook构造函数,第一个Workbook读取后可能移动流指针,甚至在异常场景下关闭流。 - 长期进程资源泄漏:服务长期运行导致文件句柄耗尽,系统强制回收资源时关闭了当前流。
- NPOI版本bug:特定版本的NPOI在流处理逻辑中存在未妥善处理的异常,导致流被意外关闭。
针对性解决方案
确保文件复制完成
复制文件后,通过验证文件大小稳定来确认写入完成:File.Copy(fileNameDownload, path); long prevSize = 0; int retryCount = 0; while (retryCount < 5) { var fileInfo = new FileInfo(path); long currentSize = fileInfo.Length; if (currentSize == prevSize) break; prevSize = currentSize; Thread.Sleep(1000); retryCount++; }避免流重复使用
针对不同Excel文件类型,使用独立的流读取:var fileExt = Path.GetExtension(path).ToLower(); if (fileExt == ".xlsx") { using (var fs = new FileStream(path, FileMode.Open, FileAccess.Read, FileShare.Read)) { var xlsxBook = new XSSFWorkbook(fs); // 业务处理逻辑 } } else if (fileExt == ".xls") { using (var fs = new FileStream(path, FileMode.Open, FileAccess.Read, FileShare.Read)) { var xlsBook = new HSSFWorkbook(fs); // 业务处理逻辑 } }隔离文件读取
将文件读取到内存流后再交给NPOI处理,彻底避免外部进程干扰:byte[] fileBytes = File.ReadAllBytes(path); var fileExt = Path.GetExtension(path).ToLower(); using (var ms = new MemoryStream(fileBytes)) { if (fileExt == ".xlsx") { var xlsxBook = new XSSFWorkbook(ms); // 业务处理逻辑 } else if (fileExt == ".xls") { var xlsBook = new HSSFWorkbook(ms); // 业务处理逻辑 } }排查资源泄漏
使用Windows资源监视器查看进程的文件句柄数量,或通过Process Monitor跟踪文件访问事件,确认是否存在未释放的文件句柄。升级NPOI版本
切换到最新稳定版的NPOI,修复已知的流处理相关bug。
内容的提问来源于stack exchange,提问作者Wolfware
相关产品推荐
相关产品推荐

