ZipArchive压缩单个文件必须用using确保Dispose()调用,否则ZIP中央目录未写入导致损坏;SharpZipLib解压中文路径需指定Encoding.UTF8或UseUnicodeAsNecessary=true;MemoryStream反复使用需重置Position=0;大文件应避免内存流而改用FileStream。

ZipArchive 压缩单个文件时,using 语句容易漏掉 Dispose() 导致 ZIP 损坏
用 ZipArchive 压缩文件,如果只写 new ZipArchive(stream, ZipArchiveMode.Create) 却没显式调用 Dispose() 或用 using 包裹,ZIP 文件会写不全——打开提示“压缩包损坏”或解压后内容为空。
根本原因是:ZIP 的中央目录(central directory)必须在流关闭前写入,而 Dispose() 才真正触发写入逻辑。没它,就只剩一个不完整的 ZIP 头。
- 必须用
using (var archive = new ZipArchive(stream, ZipArchiveMode.Create)) { ... } - 别手动
new后忘archive.Dispose() - 流(比如
FileStream)也得用using,否则可能被锁住 - 别在
archive.CreateEntry()后直接返回,entry 的Open()流也得写完再关
SharpZipLib 解压含中文路径的 ZIP 时乱码,不是编码问题而是 ZipFile 构造方式不对
SharpZipLib 默认按 DOS 编码(IBM437)读取文件名,遇到 UTF-8 编码的 ZIP(比如 Windows 10/11 默认生成的),中文路径直接变成 ???.txt。这不是你文件名写错了,是库没被告知该用什么编码解析 ZIP 元数据。
关键点在于:必须传入 Encoding.UTF8 给 ZipFile 构造函数,而不是依赖默认行为。
- 错:
var zip = new ZipFile(filePath)→ 用 IBM437,中文路径崩 - 对:
var zip = new ZipFile(filePath) { UseUnicodeAsNecessary = true }(推荐) - 或更明确:
var zip = new ZipFile(filePath, Encoding.UTF8) - 注意:
UseUnicodeAsNecessary = true要求 ZIP 文件本身标记了 UTF-8 标志位(很多工具生成时已设),比硬指定编码更稳妥
ZipArchive 和 SharpZipLib 在内存流中反复压缩/解压,不重置 Position 就会读空或写失败
用 MemoryStream 做 ZIP 中转很常见,但两个库对流位置的处理习惯不同:ZipArchive 写完后 Position == Length,SharpZipLib 解压时却默认从 Position == 0 开始读——不重置就会“读到 EOF”,解压结果为空。
反过来,用 SharpZipLib 压缩后没重置 Position = 0,再拿给 ZipArchive 解压,也会报 InvalidDataException: End of Central Directory record could not be found。
- 写完 ZIP 到
MemoryStream后,解压前务必stream.Position = 0 - SharpZipLib 的
ZipFile构造后,内部流位置不变;但GetInputStream()返回的流位置也不一定是 0,别假设 - 用
ToArray()拷贝一份再操作,比反复Seek()更不容易出错(尤其多线程场景)
大文件压缩时 ZipArchive 内存暴涨,不是代码写错,是没开流式写入
ZipArchive 默认把整个 ZIP 结构缓存在内存里,直到 Dispose() 才刷盘。压缩几个 100MB 的文件,MemoryStream 可能吃掉 1.5 倍内存——不是泄漏,是设计如此。
解决办法只有一个:换用基于磁盘的 FileStream,并确保 leaveOpen = false(SharpZipLib 同理)。内存流只适合小文件(
- 避免:
var ms = new MemoryStream(); using var archive = new ZipArchive(ms, ...) - 推荐:
using var fs = new FileStream("out.zip", FileMode.Create); using var archive = new ZipArchive(fs, ...) - SharpZipLib 的
ZipOutputStream同样建议直连FileStream,别套MemoryStream - 真要内存中处理大 ZIP?考虑分块 +
DeflateStream手动打 ZIP 包头,但复杂度陡增,一般没必要
最常被忽略的其实是流生命周期和编码标记——这两个点卡住的人,远多于语法或 API 不熟。


















