ZipFile.CreateFromDirectory要求目标路径存在且源目录不能为根目录,解压时目标目录必须不存在,否则抛异常;精细控制需用ZipArchive,注意跨平台路径、编码及安全过滤。

用 ZipFile.CreateFromDirectory 压缩目录时路径必须存在
这个方法不会自动创建父目录,如果目标 ZIP 文件路径的上层文件夹不存在(比如想存到 C:ackup‚4rchive.zip,但 2024 文件夹还没建),会直接抛 DirectoryNotFoundException。
实操建议:
- 调用前先用
Directory.CreateDirectory(Path.GetDirectoryName(zipPath))确保路径就绪 - 不要传入空字符串或仅含空格的
sourceDirectoryName,否则报ArgumentException - 源目录不能是根目录(如
"C:"),会触发IOException—— 这是 .NET 的硬限制,不是权限问题 - 默认压缩级别是
Optimal,若要更快可显式传CompressionLevel.Fastest,但压缩率明显下降
解压用 ZipFile.ExtractToDirectory 时目标文件夹不能已存在
和很多人直觉相反:这个方法要求 destinationDirectoryName 必须是**不存在的空目录**。如果该路径已存在(哪怕是个空文件夹),会直接抛 IOException:“The directory 'xxx' already exists.”
实操建议:
- 解压前加判断:
if (Directory.Exists(destDir)) Directory.Delete(destDir, true); - 或者换用更可控的方式:先新建临时空目录,再调用
ExtractToDirectory,最后按需移动内容 - 注意它不支持覆盖已有同名文件 —— 即使目标文件存在且只读,也会失败,不像命令行工具那样带 -o 参数
需要精细控制(如过滤文件、设置密码、流式处理)就得绕开 ZipFile 类
ZipFile 是高层封装,方便但死板。真要跳过某些文件、改写条目名、或从 Stream 而非磁盘读写 ZIP,必须用底层的 ZipArchive。
常见场景与要点:
- 从内存流压缩:用
new ZipArchive(memoryStream, ZipArchiveMode.Create),然后CreateEntry写入,最后别忘了memoryStream.Position = 0才能读取 - 解压时跳过隐藏文件:
foreach (var entry in archive.Entries.Where(e => !e.FullName.StartsWith("__MACOSX") && !e.Name.StartsWith("."))) - ZIP 不原生支持密码 ——
ZipArchive完全不处理加密,得靠第三方库(如SharpZipLib)或系统级工具 - 大文件解压容易 OOM:避免一次性
entry.Open().ReadAllBytes(),改用CopyTo流式落地
跨平台要注意 ZipArchive 的路径分隔符和大小写敏感性
Windows 上 ZipArchive 对路径不敏感,但 Linux/macOS 下,entry.FullName 里的反斜杠 会被当字面量处理,导致解压出错乱路径;同时大小写也严格匹配。
关键处理点:
- 压缩前统一用正斜杠:
entryName.Replace("\", "/") - 避免在 ZIP 中存绝对路径(如
"C:/data/file.txt"),一律用相对路径 - 解压时检查
entry.FullName是否含..,防止路径遍历攻击 ——ZipArchive不做校验,得自己Path.GetRelativePath或正则过滤 - .NET 6+ 在 Linux 上对 ZIP 中的中文文件名支持仍不稳定,建议用
Encoding.UTF8显式指定编码(需反射设置ZipArchiveEntry内部字段,或换 SharpZipLib)
真正卡住人的往往不是“怎么压”,而是“为什么解出来少文件”“为什么路径变成乱码”“为什么一解压就崩”。这些细节藏在文档角落,但实际部署时每个都可能让整个归档流程失败。











