如何用SevenZipCompressor实现多内存流压缩及SharpZipLib的PutNextEntry等效功能?
嘿,我来帮你理清这个问题!在SevenZipSharp(也就是你用的SevenZipCompressor所属的库)里,并没有和SharpZipLib的PutNextEntry完全一一对应的方法——毕竟两个库的设计思路略有不同。不过要实现多个内存流压缩到单个归档文件的需求,我们可以通过自定义IArchiveFileCallback来模拟类似PutNextEntry的逐条添加效果,这是最灵活高效的方式。
核心思路
SharpZipLib的PutNextEntry是手动逐个向压缩包添加条目并写入数据,而SevenZipSharp更偏向于通过回调机制来批量处理多个条目。我们需要自定义一个回调类,告诉压缩器每个条目的元数据(比如文件名、大小)和对应的内存流数据源。
完整代码示例
首先定义处理内存流的回调类:
using System.Collections.Generic; using System.IO; using SevenZip; public class MemoryStreamArchiveCallback : IArchiveFileCallback { private readonly List<(string EntryName, MemoryStream DataStream)> _archiveEntries; private int _currentEntryIndex = -1; public MemoryStreamArchiveCallback(List<(string, MemoryStream)> entries) { _archiveEntries = entries; } // 处理操作结果(可选,比如捕获压缩失败的情况) public void SetOperationResult(OperationResult result) { if (result != OperationResult.Ok) { // 这里可以添加错误处理逻辑,比如日志记录 } } // 提供条目的属性(文件名、大小等) public void GetProperty(int index, ItemPropId propId, ref object value) { switch (propId) { case ItemPropId.Path: value = _archiveEntries[index].EntryName; break; case ItemPropId.Size: value = _archiveEntries[index].DataStream.Length; break; // 还可以按需设置其他属性,比如修改时间、是否加密等 } } // 提供条目的数据流 public void GetStream(int index, out Stream stream, ArchiveStreamType streamType) { stream = null; if (streamType == ArchiveStreamType.Data) { // 一定要重置流的位置到开头,否则压缩器会从当前位置开始读取(可能读不到数据) _archiveEntries[index].DataStream.Position = 0; stream = _archiveEntries[index].DataStream; } } }
然后使用这个回调来压缩你的多个内存流:
// 假设你的fileByteList是包含二进制数据的集合,先转换成内存流列表 var archiveEntries = new List<(string, MemoryStream)>(); int fileCount = 0; foreach (var fileItem in fileByteList) { var ms = new MemoryStream(fileItem.Binary); // 这里可以自定义每个条目的文件名,比如根据业务规则命名 archiveEntries.Add(($"document_{++fileCount}.bin", ms)); } using (var compressedOutputStream = new MemoryStream()) { var compressor = new SevenZipCompressor(); compressor.CompressionMethod = CompressionMethod.Lzma2; compressor.CompressionLevel = CompressionLevel.Normal; // 关键调用:传入输出流、自定义回调,以及条目名称数组(顺序要和archiveEntries一致) compressor.CompressFiles( compressedOutputStream, new MemoryStreamArchiveCallback(archiveEntries), archiveEntries.Select(e => e.Item1).ToArray() ); // 现在compressedOutputStream就是包含多个条目的压缩包了 // 你可以将其保存到文件、返回给前端,或者做其他处理 compressedOutputStream.Position = 0; // 示例:保存到本地文件 // using (var fs = File.Create("multi_files.7z")) // { // compressedOutputStream.CopyTo(fs); // } }
补充说明
- 你之前尝试的
CompressStream方法默认只能处理单个流,并且用DefaultItemName作为唯一的条目名称,所以没法直接用来添加多个文件。 - 自定义回调的方式完全在内存中处理,不需要写入临时文件,性能更优。
- 记得处理内存流的释放(如果不需要保留的话,可以在回调里或者压缩完成后Dispose,不过示例中用了using包裹输出流,其他流可以根据业务需求管理)。
内容的提问来源于stack exchange,提问作者asdf_enel_hak
相关产品推荐
相关产品推荐

