zipfile.createfromdirectory压缩为空主因是源目录不存在、为空或路径错误,且不压缩空子目录;extracttodirectory解压报错因目标目录已存在或含危险路径,需预删目录并校验路径安全性。

ZipFile.CreateFromDirectory 和 ZipFile.ExtractToDirectory 足够用,但默认行为和边界条件不处理好,一跑就崩——不是 API 不行,是你没绕过它的硬限制。
ZipFile.CreateFromDirectory 为什么压缩出来体积大或为空
体积大是因为默认用了 CompressionLevel.Fastest,不是 Optimal;为空则大概率是源目录根本不存在、路径拼错,或者目录下真没文件(它不压缩空子目录,也不报错)。
- 必须显式传第三个参数:
CompressionLevel.Optimal,否则 10MB 文件压完可能还有 9.8MB - 调用前先确认:
Directory.Exists(sourcePath)且Directory.GetFiles(sourcePath, "*", SearchOption.AllDirectories).Length > 0 - 目标 ZIP 路径的父目录必须存在,
ZipFile.CreateFromDirectory不会自动创建C:\backup\这种中间目录,得自己调Directory.CreateDirectory(Path.GetDirectoryName(zipPath)) - 别传根目录(如
"C:"),会直接抛IOException
ZipFile.ExtractToDirectory 报“目录已存在”或写到奇怪位置
它要求 destinationDirectoryName 必须是**完全不存在的路径**,哪怕是个空文件夹也会抛 IOException: "The directory 'xxx' already exists.";更危险的是,它对 ZIP 内部的 ..\web.config 条目照单全收,不做任何路径校验。
- 解压前加一句:
if (Directory.Exists(extractPath)) Directory.Delete(extractPath, true); - 生产环境绝不能直接用这个方法解不可信 ZIP,恶意条目如
../../../etc/passwd会被原样写出 - 如果必须保留目标目录里原有文件,就得换
ZipArchive手动遍历,逐个检查entry.FullName是否越界:Path.GetRelativePath(extractPath, safePath).StartsWith("..")或Path.IsPathRooted(entry.FullName) - 中文路径本身没问题,但如果 ZIP 是用 GB2312 编码生成的(比如老版 WinRAR),.NET 默认 UTF-8 解码就会乱码,此时需换 SharpZipLib
想压缩单个文件或控制 ZIP 内路径结构怎么办
ZipFile.CreateFromDirectory 只认目录,传文件路径直接抛 DirectoryNotFoundException;想让 ZIP 里出现 assets/icon.png 而不是平铺在根目录,也得切到 ZipArchive。
- 压缩单个文件:用
ZipArchiveMode.Create+CreateEntry("assets/icon.png"),再从原文件流CopyTo(entry.Open()) - 条目名不能含盘符或绝对路径,否则抛
ArgumentException;推荐用Path.GetRelativePath(rootDir, file)构造安全路径 - 要模拟空文件夹(如
logs/),得手动CreateEntry("logs/")(结尾带斜杠),然后不往流里写任何内容 - 务必用
using包裹ZipArchive和所有流,否则 ZIP 结构损坏,Windows 资源管理器打不开,报错InvalidDataException: End of Central Directory record could not be found
真正容易被忽略的点不在语法,而在路径安全和资源释放:ZIP 条目名不是字符串,是潜在的路径指令;ZipArchive 的流不是可选的封装,是 ZIP 文件结构的物理组成部分。漏掉一次 using,或跳过一条 .. 校验,问题不会立刻暴露,但会在某个用户上传 ZIP 后半夜炸出来。










