商城首页欢迎来到中国正版软件门户

您的位置: 首页 > 文章列表 > 编程开发 > c#如何压缩文件为zip_c#压缩文件为zip完整教程与代码实例

c#如何压缩文件为zip_c#压缩文件为zip完整教程与代码实例

  发布于2026-07-17 阅读(0)

扫一扫,手机访问

聊到C#原生压缩,最直接的选择就是 `System.IO.Compression` 命名空间下的两个核心选手:`ZipFile.CreateFromDirectory` 和 `ZipArchive`。前者主打一个轻量省事,后者则提供更精细的控制力。但具体怎么选,背后有不少细节值得推敲。

c#如何压缩文件为zip_c#压缩文件为zip完整教程与代码实例

System.IO.Compression 压缩文件为 ZIP 是最轻量、无需第三方库的方案,但默认不支持密码保护和分卷,且对中文路径需额外处理编码问题。这一点,很多初次接触的同学容易忽略。

ZipFile.CreateFromDirectory 批量压缩整个文件夹

这算是最省事的方案了,适合打包一个完整目录。它内部自动处理文件遍历、时间戳、目录结构,一调用就完事。但几个限制得心里有数:

  • 源目录路径必须是绝对路径,或者确保相对路径能被正确解析,不然会抛出 DirectoryNotFoundException
  • 目标 ZIP 文件若已存在,会直接覆盖——没有提示,也不会抛异常,所以操作前最好自己确认一下。
  • 压缩级别只能选 CompressionLevel.OptimalFasterNoCompression,不能设为自定义值,灵活性有限。
  • 中文文件名是个特殊坑。.NET 6+ 默认使用 UTF-8 编码写入 ZIP 中央目录,解压兼容性不错;但 .NET Framework 4.8 及更早版本默认用系统 OEM 编码,这可能导致 WinRAR 等老工具解压时出现乱码。遇到这种情况,就得改用 ZipArchive 手动控制编码了。
using System.IO.Compression;

ZipFile.CreateFromDirectory(@"C:\myfolder", @"C:\output.zip", CompressionLevel.Optimal, includeBaseDirectory: false);

ZipArchive 精确控制单个文件/子路径压缩

当需要跳过某些文件、重命名 ZIP 内路径、添加空目录,或统一设置编码时,ZipArchive 是唯一选择。它底层更灵活,但同时也要自己管理 ZipArchiveEntry 的创建与流写入,工作量稍微大一些。

  • 构造 ZipArchive 时必须传入可写的 FileStream,且 lea veOpen: false 更安全,避免文件句柄泄漏。
  • 添加文件时,archive.CreateEntry 的第一个参数是 ZIP 内部路径,支持斜杠分隔的子目录形式,比如 "docs/readme.txt",但不能以 / 开头。
  • 写入内容必须通过 entry.Open() 获取的流来完成,且必须完全写完再 Dispose,否则条目会损坏。
  • 要支持中文名且兼顾旧解压工具,可在创建 ZipArchive 时传入 new ZipArchiveOptions { CodePage = 65001 }(仅 .NET 6+ 支持)。
using (var fs = File.Create(@"C:\custom.zip"))
using (var archive = new ZipArchive(fs, ZipArchiveMode.Create, lea veOpen: false))
{
    var entry = archive.CreateEntry("config/appsettings.json");
    using (var entryStream = entry.Open())
    using (var fileStream = File.OpenRead(@"D:\appsettings.json"))
    {
        fileStream.CopyTo(entryStream);
    }
}

压缩单个文件时别漏掉 includeBaseDirectory: false

如果误用 ZipFile.CreateFromDirectory 去“压缩一个文件”,常见做法是把它放进临时文件夹再压缩——这时若忘记设 includeBaseDirectory: false,ZIP 里就会多一层文件夹,比如 temp\myfile.txt 而非直接 myfile.txt,使用起来很不方便。

  • 更干净的做法是不用 CreateFromDirectory,改用 ZipArchive 直接添加单文件(见上一节)。
  • 如果坚持用 CreateFromDirectory,务必确保临时目录下只有目标文件,且调用时显式传 includeBaseDirectory: false
  • 注意:该参数对空目录无效;若源目录为空,生成的 ZIP 也会为空(不含任何条目)。

解压时路径穿越漏洞必须手动过滤

必须警惕的是,ZipFile.ExtractToDirectoryZipArchive.ExtractAll 默认不做路径校验。恶意 ZIP 若包含 ../../../etc/passwd 这类路径,可能覆写系统文件。这不是 .NET 的 bug,而是 ZIP 规范允许任意路径,防御责任在使用者身上。

  • 提取前,对每个 ZipArchiveEntry.FullName 调用 Path.GetFullPath,并检查是否仍落在目标解压目录内。
  • 推荐用 Path.IsPathRooted(entry.FullName) 快速拦截绝对路径,再用 entry.FullName.Contains("..") 做初步筛查(注意跨平台路径分隔符)。
  • 不要依赖 entry.Name,它只返回最后一段,无法反映完整路径结构。

真正麻烦的,往往不是压的过程,而是压完之后,别人能不能正常解压、文件名会不会乱码、有没有人故意塞个超长路径来搞事情——这些细节不写进代码里,上线后就是事故。

本文转载于:https://www.php.cn/faq/2334381.html 如有侵犯,请联系zhengruancom@outlook.com删除。
免责声明:正软商城发布此文仅为传递信息,不代表正软商城认同其观点或证实其描述。

热门关注