用 ZipArchive
打开 ZIP 时必须指定 ZipArchiveMode.Update
默认的
ZipArchive构造方式(如只传
Stream)是只读模式,直接调用
CreateEntry会抛出
NotSupportedException。必须显式传入
ZipArchiveMode.Update,且底层流不能是只读的(比如
File.OpenRead()就不行)。 使用
File.Open(..., FileMode.Open, FileAccess.ReadWrite)或
File.Open(..., FileMode.OpenOrCreate, FileAccess.ReadWrite)如果 ZIP 文件不存在,
FileMode.Open会抛
FileNotFoundException,建议先检查文件是否存在,再选
OpenOrCreate别用
MemoryStream做更新目标——它不支持随机写入,
ZipArchiveMode.Update会失败
ZipArchive.CreateEntry
会覆盖同名文件,但不会自动删除旧条目
ZIP 是基于条目(entry)的扁平结构,没有“目录”概念;添加同名路径的 entry 时,
CreateEntry不报错,但后续写入会覆盖该路径的内容。但注意:原 ZIP 中已存在的同名 entry 并不会被自动清理——实际效果取决于 ZIP 工具如何解析重复路径(多数解压工具取最后一个)。真正安全的更新需手动删除旧 entry。 遍历
archive.Entries,用
entry.FullName.Equals("path/in/zip.txt", StringComparison.OrdinalIgnoreCase) 查找
调用 entry.Delete()(仅在
Update模式下可用) 再
CreateEntry+ 写入新内容 注意:.NET 6+ 支持
Delete();.NET 5 及更早版本不支持,只能重建整个 ZIP
写入内容后必须显式调用 stream.Flush()
和 archive.Dispose()
ZipArchive的更新是延迟写入的:entry 创建、流写入都不立即落盘。只有在
Dispose()(或
using块结束)时才真正重写 ZIP 文件头和中央目录。漏掉这步会导致 ZIP 损坏或新增文件不可见。 务必用
using (var archive = new ZipArchive(stream, ZipArchiveMode.Update)) { ... }
不要提前 stream.Close()或
stream.Dispose(),否则
archive.Dispose()会失败 如果手写
try/finally,确保
archive.Dispose()在
finally中执行
追加文件时路径分隔符必须用正斜杠 /
ZIP 规范要求内部路径使用
/,即使在 Windows 上用
Path.Combine生成的是 ,也会导致解压时路径异常(如创建出名为
"folderile.txt"的单个文件,而非子目录结构)。 用
entryName.Replace("\", "/") 或 Path.GetRelativePath(root, fullPath).Replace("\", "/")
避免以 /开头(如
/data/file.txt),ZIP 解析器可能忽略前导斜杠,导致路径错位 空目录无法直接添加——ZIP 没有目录 entry,只能靠文件路径隐含,例如
"logs/"不合法,但
"logs/empty.txt"可以让解压工具创建
logs目录 .NET 的 ZIP 更新能力很基础,不支持压缩级别调整、加密、跨磁盘追加等操作;真要高频修改 ZIP,不如用
SharpZipLib或
DotNetZip这类库——它们暴露更多控制点,但代价是引入第三方依赖。
