如何在C#中创建含文件的zip归档并将其添加到外层zip压缩包
问题核心原因
你的代码存在两个逻辑错误:
- 外层总归档被放在分组循环内部,每次循环都会重新创建,直接覆盖之前写入的内容
- 内外两层
ZipArchive共用了同一个MemoryStream,无法生成两个独立的zip结构
修正后的实现代码
// 提前创建总归档对应的内存流,全程只实例化一次 using var totalArchiveStream = new MemoryStream(); // 初始化总归档,开启leaveOpen保证流在归档释放后还能读取内容 using var totalArchive = new ZipArchive(totalArchiveStream, ZipArchiveMode.Create, true); // 遍历日期分组 foreach (var (day, messagesPerDay) in messages.GroupBy(x => x.Date).ToDictionary(x => x.Key, x => x.ToList())) { // 每个按日分组的子归档单独使用独立内存流 using var dayArchiveStream = new MemoryStream(); using (var dayArchive = new ZipArchive(dayArchiveStream, ZipArchiveMode.Create, true)) { // 写入当日所有文件到子归档 foreach (var message in messagesPerDay) { var fileEntry = dayArchive.CreateEntry(message.FileName, CompressionLevel.Fastest); var contentBytes = XmlHelper.SerializeWin1251(message).ToArray(); using var entryStream = fileEntry.Open(); entryStream.Write(contentBytes, 0, contentBytes.Length); } } // 子归档释放后结构已完整,写入到总归档中 var dayZipEntry = totalArchive.CreateEntry($"{day:yyyy-MM-dd}.zip", CompressionLevel.NoCompression); using var dayZipEntryStream = dayZipEntry.Open(); // 子归档流重置到起始位置再复制 dayArchiveStream.Position = 0; dayArchiveStream.CopyTo(dayZipEntryStream); } // 必须先完全释放总归档,才能生成完整的zip尾部目录结构 totalArchive.Dispose(); // 最终总zip的字节数组,可用于保存到文件/接口返回等场景 var totalZipBytes = totalArchiveStream.ToArray();
注意说明
- 子归档写入总归档时用
CompressionLevel.NoCompression是因为子zip本身已经做过压缩,二次压缩不会明显缩小体积,还会额外消耗性能,你可以根据实际需求调整压缩等级。 - 如果需要将最终结果写入本地文件,直接把
totalZipBytes写入后缀为.zip的文件即可。
内容的提问来源于stack exchange,提问作者Nicolas
相关产品推荐
相关产品推荐

