You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

C#.NET创建多条目Zip文件报错、压缩包损坏问题求解

C# ZipArchive 生成损坏压缩包问题修复

问题复现

从Blob存储拉取文档打包ZIP下载的接口,首次运行时在zar.CreateEntry(name)位置抛出异常:

System.IO.IOException: 'Entries cannot be created while previously created entries are still open.'

手动为条目写入流添加str.Close()调用后,接口可正常返回文件,但下载得到的压缩包用WinZip解压时报错unable to seek to beginning of Central Directory,压缩包无法正常打开。

问题根因

两个报错分别由两个代码逻辑错误导致:

  1. 条目流未释放:ZipArchive在创建模式下同一时间仅允许打开一个可写条目流,上一个条目写入完成后如果没有释放对应流,直接创建下一个条目就会触发第一个IO异常。手动调用Close()虽然解决了这个问题,但写法存在资源泄漏风险。
  2. 流指针操作时机错误:这是压缩包损坏的核心原因。ZipArchive在Dispose(即退出using代码块)时,才会将ZIP文件格式必需的中央目录元数据写入到底层流。原代码在ZipArchive的using块内部就执行outms.Seek(0, SeekOrigin.Begin),此时中央目录还未写入,后续ZipArchive写入元数据时流位置已经被改动,最终生成的ZIP文件中央目录位置非法,解压工具无法读取就会抛出对应错误。

正确实现代码

[HttpPost]
public FileContentResult DownloadDocumentsByDocIDZIP(List<int> documentIDs)
{
    List<Document> docs = new List<Document>();
    foreach (int docId in documentIDs)
    {
        if (docId != 0)
        {
            docs.Add(documentService.GetDocumentByID(docId, false));
        }
    }

    MemoryStream outms = new MemoryStream();
    // 传入leaveOpen: true,避免ZipArchive释放时关闭底层MemoryStream
    using (ZipArchive zar = new ZipArchive(outms, ZipArchiveMode.Create, leaveOpen: true))
    {
        foreach (Document docu in docs)
        {
            if (docu == null) continue;
            
            byte[] documentdata = documentService.DownloadDocumentData(docu.DocumentID);
            string fileName = docu.DocumentNiceName ?? docu.DocumentFileName;
            
            ZipArchiveEntry entry = zar.CreateEntry(fileName);
            // 用using块自动释放条目流,无需手动调用Close
            using (Stream entryStream = entry.Open())
            using (MemoryStream ms = new MemoryStream(documentdata))
            {
                ms.CopyTo(entryStream);
            }
        }
        // 禁止在此处移动流指针,此时ZipArchive尚未写入中央目录
    }
    // ZipArchive完成所有内容写入、释放后,再移动流指针读取全部字节
    outms.Seek(0, SeekOrigin.Begin);
    return File(outms.ToArray(), "application/zip", "documents.zip");
}

关键调整点

  • 所有流对象都通过using块包裹,自动完成资源释放,彻底避免条目流未关闭的异常,也无需手动调用Dispose/Close
  • 初始化ZipArchive时显式指定leaveOpen: true,防止底层MemoryStream被意外关闭
  • 将流指针重置操作移动到ZipArchive的using块外部,保证ZIP中央目录等元数据完整写入后再读取流内容,避免压缩包结构损坏

内容的提问来源于stack exchange,提问作者Drikus Barnard

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.26 23:09:24