C# ZipArchive以Update模式打开zip报进程占用IOException异常
问题排查与解决
这个异常是目标zip文件被持有独占锁导致的,ZipArchiveMode.Update模式打开文件时需要独占读写权限,只要有其他进程/你自己的代码持有该文件的句柄不释放,就会触发这个报错,按以下步骤排查修复:
排查步骤
- 排查外部进程占用:打开系统自带的「资源监视器」,切换到CPU标签页,在「关联的句柄」搜索框输入
RasMol.zip,即可列出所有持有该文件锁的进程。常见的占用源包括:开着压缩包预览的文件资源管理器、正在扫描文件的杀毒软件、打开了该压缩包的解压工具、正在同步文件的网盘客户端、之前调试时未正常退出的自有程序进程,找到对应进程结束占用即可。 - 排查自身代码资源泄漏:你当前贴出的代码存在明显的资源释放问题,
ZipArchive实现了IDisposable接口,你没有用using块包裹对象,只要之前有过一次同路径的zip打开操作未正常释放,文件句柄就会一直被当前进程持有,后续打开就会报错。
修复方案
- 按实际需求选择打开模式:你当前的逻辑只是读取压缩包内条目的修改时间、大小两个元数据,完全不需要用
ZipArchiveMode.Update——这个模式是专门给新增/删除/修改压缩包内容场景用的,会强制申请独占权限。只读场景直接用ZipArchiveMode.Read即可,该模式下打开文件只申请共享读权限,大幅降低占用冲突概率,性能也更好。 - 所有
ZipArchive实例必须用using块包裹,保证操作完成后立刻释放文件句柄,不要等GC自动回收。 - 如果后续确实需要用Update模式修改压缩包,可以补充简单的重试逻辑,碰到占用时等待几百毫秒再重试,应对杀毒软件扫描、网盘同步这类短暂的临时占用。
修复后的代码如下:
public void ReplaceEntry(string fileName) { var infoList = new List<RPPXFileEntry>(); // using保证资源及时释放,只读场景用Read模式 using (ZipArchive Archive = ZipFile.Open(this.sourcePath, ZipArchiveMode.Read)) { foreach (ZipArchiveEntry entry in Archive.Entries) { if (entry.Name == fileName) { var rppxEntry = new RPPXFileEntry { Modify = entry.LastWriteTime, Size = entry.Length }; infoList.Add(rppxEntry); } } } this.AllEntries = infoList; }
额外注意:调试阶段如果反复触发该异常,优先去任务管理器结束掉所有未正常退出的你的程序进程(包括调试宿主进程*.vshost.exe),调试中断时代码不会执行资源释放逻辑,很容易造成句柄泄漏锁文件;另外跑代码前关掉打开了该zip路径的资源管理器窗口,Windows自带的压缩文件夹功能会主动给zip文件加锁。
内容的提问来源于stack exchange,提问作者Adrian
相关产品推荐
相关产品推荐

