用 ZipFile.CreateFromDirectory
打包整个文件夹最简单
这是 .NET 4.5+ 内置方案,无需第三方库,一行代码就能把整个文件夹打成 ZIP。但要注意它不支持密码、不支持增量更新、也不处理空文件夹(会跳过)。
常见错误是路径权限不足或目标 ZIP 已被占用,导致
IOException;另外源路径末尾加不加反斜杠不影响结果,但目标 ZIP 文件路径必须包含完整文件名(如
"output.zip"),不能只写目录。 确保源目录存在且可读,目标 ZIP 的父目录存在且可写 如果要排除某些子目录或文件,得先复制筛选后的结构到临时目录再压缩 不支持中文路径在旧版 Windows 上可能出乱码,建议统一用 UTF-8 编码环境(.NET Core / .NET 5+ 默认支持)
用 ZipArchive
精确控制每个文件的压缩行为
当你需要跳过特定文件、修改压缩级别、添加空目录、或从流写入 ZIP 时,
ZipArchive是唯一选择。它底层更灵活,但也更容易出错——比如忘记调用
Dispose()会导致 ZIP 文件损坏或被锁住。
典型场景:把多个分散的文件打包,或边生成内容边写入 ZIP(如日志归档)。
用CompressionLevel.Optimal或
Faster明确指定压缩强度,默认是
Optimal添加空目录需手动创建
ZipArchiveEntry,名字以
"/"结尾(如
"logs/") 从
FileStream写入时,务必用
FileMode.Create,否则可能追加写入导致 ZIP 结构异常
处理中文文件名必须设 UseZip64 = Zip64Option.AsNeeded
默认情况下,
ZipArchive在 .NET Framework 下对中文路径写入 ZIP 后,用 Windows 自带解压工具打开会显示乱码或无法识别。这不是编码问题,而是 ZIP 标准兼容性问题。
根本原因是传统 ZIP 使用 IBM Code Page 437 编码存文件名,而 .NET 默认没启用 ZIP64 扩展和 UTF-8 文件名标记(bit 11 in general purpose bit flag)。解决方法是在创建
ZipArchive时显式启用:
using (var archive = new ZipArchive(outputStream, ZipArchiveMode.Create, leaveOpen: true))
{
archive.UseZip64 = Zip64Option.AsNeeded;
// … 添加条目
}
注意:
UseZip64在 .NET Core 3.0+ 和 .NET 5+ 中已默认为
AsNeeded,但 .NET Framework 4.5–4.8 仍需手动设置。
第三方库 SharpZipLib
适合老项目或特殊需求
如果你还在维护 .NET Framework 2.0–4.0 项目,或者需要 ZIP 分卷、AES 加密、BZIP2 压缩等高级功能,
SharpZipLib仍是可靠选择。NuGet 包名是
SharpZipLib,不是
ICSharpCode.SharpZipLib(后者是旧命名)。
容易踩的坑是混淆
FastZip和
ZipOutputStream:前者适合整目录一键压缩,后者适合精细控制流式写入;另外它的默认编码是
System.Text.Encoding.Default,中文需手动设为
Encoding.UTF8并开启
IsUnicodeText = true。 使用
FastZip时,
ExcludeFilter接收正则字符串,不是 glob 模式
ZipOutputStream.PutNextEntry()必须在写入前调用,且
entry.Size要提前设好(流式压缩除外) 加密 ZIP 只支持传统 ZipCrypto(弱),不支持现代 AES,别用于敏感数据 .NET 自带 ZIP API 足够应付大多数打包需求,但细节决定成败:路径编码、空目录、压缩级别、资源释放——这些地方一疏忽,ZIP 就打不开或解压失败。真正难的不是“怎么压缩”,而是“怎么让别人用任意工具都解得开”。
