C# 文件压缩解压方法 C#如何使用ZipArchive进行压缩

来源:这里教程网 时间:2026-02-21 17:42:36 作者:

ZipArchive 压缩文件时为什么生成的 zip 打不开?

常见原因是未正确调用

Dispose()
或未关闭流,导致 zip 文件头不完整。.NET 的
ZipArchive
依赖流的最终刷新和关闭来写入中央目录结构——如果流提前释放或未显式关闭,压缩包看似生成成功,但双击打开会提示“无法读取”或“文件损坏”。

必须使用
using
语句包裹
ZipArchive
和其底层
FileStream
,确保资源释放顺序正确
不要手动调用
stream.Close()
后再进
using
,会导致重复关闭异常
若目标路径已存在同名 zip 文件,
FileMode.Create
会清空它,但旧文件句柄未释放时可能引发
IOException
using (var stream = new FileStream("output.zip", FileMode.Create))
using (var archive = new ZipArchive(stream, ZipArchiveMode.Create))
{
    var entry = archive.CreateEntry("hello.txt");
    using (var writer = new StreamWriter(entry.Open()))
    {
        writer.Write("Hello from ZipArchive!");
    }
} // ← 关键:两个 using 都在此结束,保证中央目录写入完成

如何向已有 zip 文件添加新文件(非覆盖)?

ZipArchiveMode.Update
支持在现有 zip 中增删条目,但它要求底层流支持随机读写(如
FileStream
),且不能是只读打开。直接用
FileMode.Open
+
FileAccess.ReadWrite
是必要前提;用
FileMode.Append
或只读流会抛出
NotSupportedException

添加同名条目会自动替换原内容;删除条目需调用
entry.Delete()
(.NET 6+)
修改后必须让
ZipArchive
正常 dispose,否则变更不会落盘
不建议对网络路径或 UNC 路径使用
Update
模式,容易因锁竞争失败
using (var stream = new FileStream("data.zip", FileMode.Open, FileAccess.ReadWrite))
using (var archive = new ZipArchive(stream, ZipArchiveMode.Update))
{
    var newEntry = archive.CreateEntry("new.log");
    using (var writer = new StreamWriter(newEntry.Open()))
    {
        writer.WriteLine(DateTime.Now);
    }
}

解压时如何避免路径遍历漏洞(如 ../web.config)?

ZipArchiveEntry.FullName
可能包含恶意路径片段,直接拼接
Path.Combine(extractTo, entry.FullName)
会导致文件被写到 zip 外目录。.NET 不做默认过滤,必须手动校验。

Path.GetRelativePath(".", entry.FullName)
无法解决,因
..
在开头时会返回绝对路径
推荐做法:用
Path.GetFileName(entry.Name)
提取纯文件名,或用
Path.IsPathRooted()
+
entry.FullName.Contains("..")
拒绝非法条目
更稳妥的是逐段检查
Path.GetFullPath(Path.Combine("fake", entry.FullName))
是否仍以预期根目录开头
string extractTo = @"C:\unzip";
foreach (ZipArchiveEntry entry in archive.Entries)
{
    string destinationPath = Path.GetFullPath(Path.Combine(extractTo, entry.FullName));
    if (!destinationPath.StartsWith(Path.GetFullPath(extractTo) + Path.DirectorySeparatorChar))
    {
        throw new InvalidOperationException($"Suspicious path: {entry.FullName}");
    }
    entry.ExtractToFile(destinationPath, overwrite: true);
}

ZipArchive 和第三方库(如 SharpZipLib)的关键差异

ZipArchive
是 .NET Framework 4.5+ / .NET Core 内置方案,轻量、无额外依赖,但功能有限:不支持 ZIP64(超 4GB 文件)、不支持密码保护、不支持分卷压缩。遇到这些需求必须换库。

压缩大文件(>2GB)时,
ZipArchive
可能静默截断或抛
InvalidDataException
,而 SharpZipLib 默认启用 ZIP64
需要 AES 加密?
ZipArchive
完全不支持;SharpZipLib 和 DotNetZip 提供
ZipEntry.IsAesEncrypted
内存敏感场景:用
ZipArchive
解压时,
entry.Open()
返回流不缓存全文,适合边读边处理;但压缩时所有内容必须先写入流,无法真正流式压缩

真正要稳定处理生产环境 zip,别只盯着

ZipArchive
——它只是基础工具,不是万能解法。路径校验、大文件、加密、编码兼容性(如中文文件名),每个点都得单独补漏。

相关推荐