zipfile.createfromdirectory 默认压缩级别为fastest,导致体积大;需显式指定compressionlevel.optimal,并注意路径安全、中文编码及流资源释放,避免路径遍历与zip结构损坏。

直接用 ZipFile.CreateFromDirectory 压缩整个文件夹、用 ZipFile.ExtractToDirectory 解压,是最稳妥的起点;但想压缩单个文件、控制条目路径、处理中文或防路径穿越,就得切到 ZipArchive ——GZipStream 则完全不适用于 ZIP 包,它只做流式 GZIP 压缩(如 .gz 文件),和 ZIP 格式无关。
ZipFile.CreateFromDirectory 为什么压缩出来体积很大
默认压缩级别是 CompressionLevel.Fastest,不是 Optimal。不显式传参就会“快但废空间”。
- 必须手动指定第三个参数为
CompressionLevel.Optimal,否则 10MB 的文件可能只压到 9.5MB -
includeBaseDirectory: false是常用配置,避免解压后多出一层同名文件夹 - 源路径必须是**真实存在的目录**,不能是文件路径,否则抛
DirectoryNotFoundException - 目标 ZIP 文件路径若已存在,会直接抛
IOException,需提前检查并删除:if (File.Exists(zipPath)) File.Delete(zipPath);
ZipFile.ExtractToDirectory 解压时被覆盖或写错位置
它不校验 ZIP 内部路径安全性,遇到 ../../../etc/passwd 这类条目会照写不误,属于典型路径遍历漏洞。
- 生产环境绝不能直接调用,必须先过滤
entry.FullName:确保不以"..\"或"../"开头,且Path.IsPathRooted(entry.FullName) == false - 目标目录不需要预先创建,方法会自动建全路径;但如果目录已存在且含同名文件,会静默覆盖,不会清空目录
- 中文路径没问题,但若 ZIP 是用非 UTF-8 工具(如旧版 WinRAR)生成的,可能解出乱码——
ZipFile默认按 UTF-8 解码,无法切换编码
想压缩单个文件或自定义 ZIP 内路径结构
ZipFile.CreateFromDirectory 不支持,必须用 ZipArchive 手动构造。
- 用
ZipFile.Open(zipPath, ZipArchiveMode.Create)打开归档,再调CreateEntry("subdir/file.txt")指定 ZIP 内路径 - 条目名不能含盘符或绝对路径,否则抛
ArgumentException;推荐用Path.GetFileName(file)或Path.GetRelativePath(rootDir, file) - 写入内容务必用
entry.Open()获取流,再fileStream.CopyTo(entryStream),别用ReadAllBytes加载大文件到内存 - 必须用
using包裹ZipArchive和所有流,否则 ZIP 文件结构损坏,Windows 资源管理器打不开,报错InvalidDataException: End of Central Directory record could not be found
别把 GZipStream 当作 ZIP 工具来用
GZipStream 和 ZipFile 完全不是一回事:前者只压缩单个流,生成的是 .gz 文件(无目录结构、无多个文件),后者才是 ZIP 归档标准实现。
- 用
GZipStream压缩一个文件,结果是二进制 .gz,双击无法用系统自带 ZIP 工具打开 - 它不支持添加多个文件、不保存文件名、不处理目录,仅适合 HTTP 响应体压缩或日志流压缩场景
- 若你看到教程混用
GZipStream和 “ZIP 压缩”,基本是概念混淆,实际需求大概率该用ZipArchive
真正麻烦的从来不是“怎么写完”,而是“怎么不出错”:路径校验漏一项、流没 Dispose、压缩级别忘改、中文名在跨平台环境里大小写敏感——这些点不盯紧,上线后就是静默失败或安全缺口。










