
简介SharpCompress 0.37.2 是一份面向 .NET 开发者的压缩库 NuGet 离线包适合需要在项目中集成 zip、rar、7z、tar 等格式读写能力的工程师尤其适用于无法直接访问外网源、需手动引入依赖的内网或离线开发环境。压缩包共 11 个文件以 5 个 SharpCompress.dll 程序集为核心分别对应 net8.0、net6.0、netstandard2.1、netstandard2.0 与 net462 多个目标框架另含 nuspec 清单、Content_Types.xml、rels 关系文件、README.md 说明文档及 p7s 签名文件整体约 1.19MB体积轻量便于随项目分发。该库支持流式读写与多格式解压可减少自行封装底层压缩逻辑的工作量。目前已有 87 人学习下载适合需要快速补齐压缩处理能力、对照多框架程序集选型的开发者参考使用。1. 从 sharpcompress.0.37.2.zip 说起一个被低估的压缩库到底能解决什么如果你在 .NET 项目里处理过 zip、7z、tar、gzip 甚至 rar 的解压大概率绕不开一个名字SharpCompress。它不像 System.IO.Compression 那样是官方内置但在格式覆盖面上要宽得多——官方库主要管 zip 和 gzip而 SharpCompress 把 7z、rar、tar、tar.gz、tar.bz2、lzip、xz 这些常见归档格式都纳入了同一套读写接口。你拿到的 sharpcompress.0.37.2.zip 就是这个库某个版本的源码或发布包版本号 0.37.2 说明它还在 0.x 阶段API 相对稳定但仍有演进空间。这个标题背后真正的问题不是“怎么解压一个 zip”而是“当项目需要同时面对多种压缩格式、又不想为每种格式引入不同第三方库时怎么用一套代码统一处理”。SharpCompress 的价值就在这里它把归档读取抽象成 IArchive / IReader 体系写入抽象成 IWriter流式处理大文件时不需要一次性把整个归档读进内存。适合谁做桌面工具、批量文件处理、备份恢复、日志归档、安装包解析的 .NET 工程师尤其是那些被“rar 解压要额外找库、7z 又要换一套 API”折磨过的人。这一篇不打算复述官方 README而是按我实际在项目里用它的路径从引入方式、核心 API、参数配置、踩坑记录到进阶技巧把 sharpcompress 0.37.2 这个版本能落地的用法讲清楚。你如果是第一次接触可以跟着代码块直接跑如果你已经用过旧版本可以重点看参数差异和避坑部分。2. 把 SharpCompress 接进项目引入方式与最小可跑示例2.1 包引入的三种路径与版本选择拿到 sharpcompress.0.37.2.zip 之后第一件事是决定怎么把它变成项目里可引用的依赖。常见做法有三种直接引用编译好的 DLL、把源码项目加入解决方案、通过 NuGet 安装对应版本。前两种适合你需要改源码或调试内部逻辑的场景第三种适合绝大多数生产项目。如果你走 NuGet命令很简单dotnet add package SharpCompress --version 0.37.2如果你拿到的是源码 zip解压后通常会看到 SharpCompress 主项目和一些测试项目。用 dotnet CLI 把主项目加入你的解决方案dotnet sln add ./SharpCompress/SharpCompress.csproj dotnet add ./YourApp/YourApp.csproj reference ./SharpCompress/SharpCompress.csproj这里有个版本选择上的实际考量0.37.x 系列对 .NET Standard 2.0 和 .NET 6 的支持比较完整如果你的项目还在 .NET Framework 4.6.1 上也能跑但部分异步 API 会退化成同步实现。我一般会在 csproj 里显式锁定版本避免 CI 环境自动拉到更高版本导致行为变化PackageReference IncludeSharpCompress Version0.37.2 /参数说明Version 写死到补丁号是因为 0.x 阶段小版本之间偶尔会有 API 签名调整锁版本能保证本地和构建服务器行为一致。如果你确实需要升级先在一个分支上跑完解压测试用例再合并。2.2 读取 zip 的最小代码与流式处理要点引入之后最常用的入口是ArchiveFactory.Open或ZipArchive.Open。下面这段代码演示从文件路径打开一个 zip遍历条目并解压到指定目录using SharpCompress.Archives; using SharpCompress.Common; string archivePath D:\data\sample.zip; string outputDir D:\data\extracted; Directory.CreateDirectory(outputDir); using (var archive ArchiveFactory.Open(archivePath)) { foreach (var entry in archive.Entries) { if (entry.IsDirectory) continue; // 只解压 .txt 和 .csv避免释放不需要的文件 string ext Path.GetExtension(entry.Key); if (ext ! .txt ext ! .csv) continue; string destPath Path.Combine(outputDir, entry.Key); Directory.CreateDirectory(Path.GetDirectoryName(destPath)!); entry.WriteToFile(destPath, new ExtractionOptions { ExtractFullPath true, Overwrite true }); } }逻辑说明ArchiveFactory.Open会根据文件头自动识别格式不要求你提前知道是 zip 还是 7z。entry.Key是归档内的相对路径WriteToFile负责把当前条目写到磁盘。ExtractionOptions里ExtractFullPath true会保留目录结构Overwrite true表示同名文件直接覆盖。参数说明如果你处理的是不可信来源的归档ExtractFullPath要配合路径校验一起用防止../这类路径穿越。0.37.2 里WriteToFile本身不会做安全路径检查需要你自己在Path.Combine之后判断最终路径是否在 outputDir 之下。另一个参数是entry.Size可以在解压前用来估算总大小避免磁盘写满。流式处理方面如果你不想落盘可以用entry.OpenEntryStream()拿到一个只读流直接喂给后续处理逻辑using (var archive ArchiveFactory.Open(archivePath)) { var target archive.Entries.First(e e.Key.EndsWith(.csv)); using (var stream target.OpenEntryStream()) using (var reader new StreamReader(stream)) { string? line; while ((line reader.ReadLine()) ! null) { // 逐行处理内存占用与文件大小无关 } } }这种写法在解压大文件时特别有用因为不会一次性把条目内容读进 byte 数组。注意OpenEntryStream返回的流在archive释放后不可再用所以处理逻辑要放在 using 块内部。3. 写入与压缩用 SharpCompress 生成 zip 和 7z 的实操细节3.1 创建 zip 的 Writer 用法与压缩级别读取之外SharpCompress 也能写归档。创建 zip 的常见做法是用ZipArchive.Create()配合WriterOptionsusing SharpCompress.Archives; using SharpCompress.Common; using SharpCompress.Writers; string outputZip D:\data\output.zip; using (var archive ZipArchive.Create()) { archive.AddEntry(docs/readme.txt, D:\src\readme.txt); archive.AddEntry(data/report.csv, D:\src\report.csv); archive.SaveTo(outputZip, new WriterOptions(CompressionType.Deflate) { LeaveStreamOpen false }); }逻辑说明AddEntry的第一个参数是归档内路径第二个参数是本地文件路径。SaveTo触发实际写入WriterOptions指定压缩算法。zip 常用Deflate兼容性最好如果你追求更高压缩率可以用Deflate64但部分老解压工具不支持。参数说明LeaveStreamOpen设为 false 表示 SaveTo 完成后关闭内部流避免文件句柄泄漏。如果你是在内存流上操作需要设为 true 以便后续读取。压缩级别在 0.37.2 里通过WriterOptions的CompressionType间接控制没有直接的 0-9 档位这一点和某些库不同选型时要注意。3.2 7z 写入的差异与适用场景7z 的写入接口和 zip 类似但入口不同using SharpCompress.Archives.SevenZip; using SharpCompress.Common; using SharpCompress.Writers; string output7z D:\data\output.7z; using (var archive SevenZipArchive.Create()) { archive.AddEntry(logs/app.log, D:\src\app.log); archive.SaveTo(output7z, new WriterOptions(CompressionType.LZMA) { LeaveStreamOpen false }); }逻辑说明SevenZipArchive.Create()创建 7z 归档压缩类型用LZMA。7z 的优势在于压缩率通常比 zip 高尤其是文本类文件。但要注意SharpCompress 对 7z 的写入支持在 0.37.2 里是有限的——它不支持加密写入也不支持固实压缩块的自定义分块大小。如果你的场景需要这些特性得换别的方案。参数说明CompressionType.LZMA是 7z 的默认算法LZMA2在部分版本里也可用但 0.37.2 的 WriterOptions 对 7z 的可选参数较少。实际项目中我一般用 7z 做冷备份zip 做需要广泛兼容的分发。提示写入大文件时AddEntry会持有源文件句柄直到SaveTo完成。如果源文件在写入过程中被其他进程修改可能抛 IOException。稳妥做法是先复制到临时目录再添加。4. 避坑与排查SharpCompress 0.37.2 的 5 个血泪教训4.1 中文文件名乱码现象、原因与解决现象解压 zip 后中文文件名变成乱码比如“报告.csv”变成“±¨¸æ.csv”。原因zip 格式对文件名编码没有统一强制标准Windows 下常用 GBK而 SharpCompress 默认按 UTF-8 解析。如果归档创建时用的是 GBK 且没有设置 UTF-8 标志位就会乱码。解决在读取时显式指定编码。0.37.2 里可以通过ReaderOptions设置using SharpCompress.Readers; var options new ReaderOptions { ArchiveEncoding new ArchiveEncoding { Default System.Text.Encoding.GetEncoding(GBK) } }; using (var archive ArchiveFactory.Open(archivePath, options)) { // 遍历条目时文件名会按 GBK 解码 }注意ArchiveEncoding需要引用SharpCompress.Common命名空间。如果归档来源不固定可以先尝试 UTF-8失败后再回退 GBK。4.2 大文件解压内存暴涨流式与缓冲的取舍现象解压一个 2GB 的 zip 时进程内存冲到 1.5GB 以上。原因用了entry.WriteToFile之外的方式比如先把entry.OpenEntryStream()读进MemoryStream或者遍历时对每个条目调用了entry.Size之外的属性触发了内部缓冲。解决坚持用OpenEntryStream逐块读取缓冲区大小控制在 81920 字节左右。不要用StreamReader.ReadToEnd()处理大文件。如果必须拿到完整字节数组先判断entry.Size是否超过阈值超过就改用临时文件中转。4.3 加密 zip 读取失败密码传了却报错现象带密码的 zip 在ArchiveFactory.Open时直接抛 CryptographicException或者遍历到加密条目时才失败。原因SharpCompress 对加密 zip 的支持分两种ZipCrypto 和 AES。0.37.2 对 AES 加密的支持需要显式传密码且部分压缩方法组合不支持。解决打开时传入ReaderOptions的Passwordvar options new ReaderOptions { Password yourpassword }; using (var archive ArchiveFactory.Open(archivePath, options)) { // 加密条目在访问时才会真正解密 }如果仍然失败先用 7-Zip 等工具确认加密算法AES-256 在 0.37.2 里支持有限必要时先解密再处理。4.4 路径穿越ExtractFullPath 不是安全开关现象解压恶意 zip 时文件被写到了目标目录之外。原因ExtractFullPath true只是保留归档内的相对路径不会阻止../向上跳转。解决在Path.Combine之后做规范化校验string fullDest Path.GetFullPath(Path.Combine(outputDir, entry.Key)); if (!fullDest.StartsWith(Path.GetFullPath(outputDir) Path.DirectorySeparatorChar)) { throw new InvalidOperationException(检测到路径穿越: entry.Key); }这一步不能省尤其是处理用户上传的归档时。4.5 版本升级后 API 不兼容0.36 到 0.37 的变化现象从 0.36 升级到 0.37.2 后原来能编译的代码报错提示ArchiveFactory.Open重载不存在或WriterOptions构造函数参数不匹配。原因0.37 系列调整了部分命名空间和构造函数签名比如WriterOptions的压缩类型参数从枚举位置参数改成了属性初始化。解决升级前先看项目的 Release Notes把new WriterOptions(CompressionType.Deflate)改成new WriterOptions(CompressionType.Deflate) { ... }形式并检查ArchiveEncoding的引用路径。如果项目大建议先在一个分支上升级并跑完所有解压测试用例。5. 进阶技巧用 SharpCompress 做批量归档校验与格式转换5.1 批量校验归档完整性生产环境里经常需要确认一批归档文件是否损坏。SharpCompress 可以在不完整解压的情况下做基础校验遍历所有条目并尝试读取每个条目的流到末尾不落盘。using SharpCompress.Archives; bool ValidateArchive(string path) { try { using (var archive ArchiveFactory.Open(path)) { foreach (var entry in archive.Entries) { if (entry.IsDirectory) continue; using (var stream entry.OpenEntryStream()) { byte[] buffer new byte[81920]; while (stream.Read(buffer, 0, buffer.Length) 0) { } } } } return true; } catch { return false; } }这个方法的代价是完整读取一遍数据但不需要磁盘写入。对于几十 MB 的归档可以接受上 GB 的归档建议抽样校验或只检查中央目录。5.2 格式转换zip 转 tar.gz 的流式管道有时需要把 zip 转成 tar.gz 以便在 Linux 环境分发。SharpCompress 支持 tar 和 gzip 写入可以边读边写using SharpCompress.Archives; using SharpCompress.Common; using SharpCompress.Writers; using SharpCompress.Writers.Tar; using (var source ArchiveFactory.Open(D:\data\input.zip)) using (var tarStream File.Create(D:\data\output.tar.gz)) using (var writer new TarWriter(tarStream, new TarWriterOptions(CompressionType.GZip, true))) { foreach (var entry in source.Entries) { if (entry.IsDirectory) continue; using (var entryStream entry.OpenEntryStream()) { writer.Write(entry.Key, entryStream, entry.LastModifiedTime ?? DateTime.Now); } } }逻辑说明TarWriter的第二个参数true表示在 tar 外层再套 gzip 压缩。Write方法接收条目名、流和修改时间。这样转换不需要中间临时文件内存占用也稳定。参数说明TarWriterOptions的CompressionType.GZip对应 .tar.gz改成BZip2就是 .tar.bz2。entry.LastModifiedTime可能为 null用DateTime.Now兜底。5.3 一个我常用的习惯每次在项目里引入或升级 SharpCompress我会先写一个小的控制台程序把手上所有格式的样本各跑一遍zip、7z、tar、tar.gz、rar只读。跑通之后再写业务代码。这个习惯帮我提前发现了编码问题、加密兼容问题和路径穿越漏洞比在业务逻辑里调试省事得多。希望帮到你。本文还有配套的精品资源点击获取