1. 项目概述
在C#开发中,经常需要处理文件压缩和解压缩的场景。Windows操作系统原生提供了强大的ZIP文件处理功能,通过.NET Framework中的System.IO.Compression命名空间,我们可以轻松实现文件夹打包为ZIP文件的操作。这种方式相比第三方库有几个显著优势:无需额外依赖、性能稳定、与Windows系统深度集成。
我在多个实际项目中都使用过这种原生压缩方案,特别是在需要保证部署环境纯净的场合。比如在开发自动更新模块时,就采用了这种方案来打包和分发更新文件包。下面我将详细介绍具体实现方法和注意事项。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 环境准备与基础配置
2.1 引用必要的命名空间
要使用Windows自带的ZIP功能,首先需要在项目中添加对System.IO.Compression和System.IO.Compression.FileSystem的引用。对于.NET Core/.NET 5+项目,只需要通过NuGet添加System.IO.Compression.ZipFile包即可。
csharp复制// 对于.NET Framework项目
using System.IO;
using System.IO.Compression;
// 对于.NET Core/.NET 5+项目
// 需要通过NuGet安装System.IO.Compression.ZipFile
2.2 基础压缩方法
最简单的文件夹压缩只需要一行代码:
csharp复制ZipFile.CreateFromDirectory(@"C:\sourceFolder", @"C:\archive.zip");
这个方法会将sourceFolder目录下的所有文件和子目录递归地打包到archive.zip文件中。但实际项目中,我们通常需要更多控制和错误处理。
3. 高级压缩功能实现
3.1 带压缩级别的打包
Windows自带的ZIP功能支持不同的压缩级别,我们可以通过ZipFileExtensions类来实现:
csharp复制public static void CreateZipWithLevel(string sourceDir, string zipPath, CompressionLevel level)
{
// 确保源目录存在
if (!Directory.Exists(sourceDir))
throw new DirectoryNotFoundException($"Source directory not found: {sourceDir}");
// 临时目录用于中间处理
string tempDir = Path.Combine(Path.GetTempPath(), Path.GetRandomFileName());
Directory.CreateDirectory(tempDir);
try
{
// 创建空zip文件
using (var archive = ZipFile.Open(zipPath, ZipArchiveMode.Create))
{
// 添加一个空条目以确保文件创建
archive.CreateEntry("placeholder");
}
// 重新打开并添加实际内容
using (var archive = ZipFile.Open(zipPath, ZipArchiveMode.Update))
{
foreach (var file in Directory.GetFiles(sourceDir, "*", SearchOption.AllDirectories))
{
// 计算相对路径
string relativePath = file.Substring(sourceDir.Length).TrimStart(Path.DirectorySeparatorChar);
// 创建条目并设置压缩级别
var entry = archive.CreateEntry(relativePath, level);
using (var entryStream = entry.Open())
using (var fileStream = File.OpenRead(file))
{
fileStream.CopyTo(entryStream);
}
}
}
}
finally
{
// 清理临时目录
if (Directory.Exists(tempDir))
Directory.Delete(tempDir, true);
}
}
3.2 进度报告与取消支持
对于大文件夹的压缩,添加进度反馈和取消功能很有必要:
csharp复制public static async Task CreateZipWithProgressAsync(
string sourceDir,
string zipPath,
IProgress<double> progress,
CancellationToken cancellationToken)
{
var files = Directory.GetFiles(sourceDir, "*", SearchOption.AllDirectories);
long totalBytes = files.Sum(f => new FileInfo(f).Length);
long processedBytes = 0;
using (var archive = ZipFile.Open(zipPath, ZipArchiveMode.Create))
{
foreach (var file in files)
{
cancellationToken.ThrowIfCancellationRequested();
string relativePath = file.Substring(sourceDir.Length).TrimStart(Path.DirectorySeparatorChar);
var entry = archive.CreateEntry(relativePath, CompressionLevel.Optimal);
using (var entryStream = entry.Open())
using (var fileStream = File.OpenRead(file))
{
await fileStream.CopyToAsync(entryStream);
processedBytes += fileStream.Length;
double percentage = (double)processedBytes / totalBytes * 100;
progress?.Report(percentage);
}
}
}
}
4. 异常处理与安全考虑
4.1 常见异常处理
在实际使用中,可能会遇到各种异常情况:
csharp复制public static void SafeCreateZip(string sourceDir, string zipPath)
{
try
{
// 检查源目录
if (!Directory.Exists(sourceDir))
throw new DirectoryNotFoundException("Source directory does not exist");
// 检查目标路径是否可用
string zipDir = Path.GetDirectoryName(zipPath);
if (!Directory.Exists(zipDir))
Directory.CreateDirectory(zipDir);
// 检查文件是否被占用
if (File.Exists(zipPath))
