C# 文件压缩工具(支持 ZIP 打包)
C# 文件压缩解决方案,支持将多个文件打包成一个 ZIP 文件,包含密码保护、压缩级别控制、进度监控等功能。
一、项目结构
FileCompressor/
├── Program.cs # 程序入口
├── MainForm.cs # 主窗体
├── ZipManager.cs # ZIP压缩管理器
├── CompressionProgress.cs # 压缩进度监控
├── FileSelector.cs # 文件选择器
├── ZipExtractor.cs # ZIP解压管理器
└── FileCompressor.csproj
二、核心源码实现
2.1 项目文件 (FileCompressor.csproj)
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>WinExe</OutputType>
<TargetFramework>net6.0-windows</TargetFramework>
<Nullable>enable</Nullable>
<UseWindowsForms>true</UseWindowsForms>
</PropertyGroup>
<ItemGroup>
<!-- 使用 .NET 内置的压缩库 -->
<PackageReference Include="System.IO.Compression" Version="4.3.0" />
<PackageReference Include="System.IO.Compression.ZipFile" Version="4.3.0" />
<!-- 可选:使用 SharpZipLib 获得更多功能 -->
<PackageReference Include="SharpZipLib" Version="1.4.2" />
</ItemGroup>
</Project>
2.2 程序入口 (Program.cs)
using System;
using System.Windows.Forms;
namespace FileCompressor
{
internal static class Program
{
[STAThread]
static void Main()
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.Run(new MainForm());
}
}
}
2.3 主窗体 (MainForm.cs)
using System;
using System.Collections.Generic;
using System.Drawing;
using System.IO;
using System.Windows.Forms;
namespace FileCompressor
{
public partial class MainForm : Form
{
private ZipManager zipManager = new ZipManager();
private FileSelector fileSelector = new FileSelector();
private List<string> selectedFiles = new List<string>();
private string outputZipPath = "";
public MainForm()
{
InitializeComponent();
zipManager.ProgressChanged += ZipManager_ProgressChanged;
zipManager.OperationCompleted += ZipManager_OperationCompleted;
}
private void btnSelectFiles_Click(object sender, EventArgs e)
{
selectedFiles = fileSelector.SelectFiles();
UpdateFileList();
}
private void btnSelectFolder_Click(object sender, EventArgs e)
{
selectedFiles = fileSelector.SelectFolder();
UpdateFileList();
}
private void UpdateFileList()
{
lstFiles.Items.Clear();
foreach (var file in selectedFiles)
{
lstFiles.Items.Add(Path.GetFileName(file));
}
lblFileCount.Text = $"已选择 {selectedFiles.Count} 个文件";
UpdateTotalSize();
}
private void UpdateTotalSize()
{
long totalSize = 0;
foreach (var file in selectedFiles)
{
if (File.Exists(file))
{
totalSize += new FileInfo(file).Length;
}
}
lblTotalSize.Text = $"总大小: {FormatFileSize(totalSize)}";
}
private string FormatFileSize(long bytes)
{
string[] sizes = { "B", "KB", "MB", "GB", "TB" };
double len = bytes;
int order = 0;
while (len >= 1024 && order < sizes.Length - 1)
{
order++;
len = len / 1024;
}
return $"{len:0.##} {sizes[order]}";
}
private void btnSelectOutput_Click(object sender, EventArgs e)
{
SaveFileDialog saveFileDialog = new SaveFileDialog();
saveFileDialog.Filter = "ZIP文件|*.zip|所有文件|*.*";
saveFileDialog.DefaultExt = "zip";
saveFileDialog.FileName = "archive.zip";
if (saveFileDialog.ShowDialog() == DialogResult.OK)
{
outputZipPath = saveFileDialog.FileName;
txtOutputPath.Text = outputZipPath;
}
}
private void btnCompress_Click(object sender, EventArgs e)
{
if (selectedFiles.Count == 0)
{
MessageBox.Show("请先选择要压缩的文件!", "提示", MessageBoxButtons.OK, MessageBoxIcon.Warning);
return;
}
if (string.IsNullOrEmpty(outputZipPath))
{
MessageBox.Show("请选择输出文件路径!", "提示", MessageBoxButtons.OK, MessageBoxIcon.Warning);
return;
}
// 检查输出文件是否已存在
if (File.Exists(outputZipPath) && !chkOverwrite.Checked)
{
MessageBox.Show("输出文件已存在,请勾选覆盖选项或选择其他文件名!", "提示", MessageBoxButtons.OK, MessageBoxIcon.Warning);
return;
}
// 禁用按钮
btnCompress.Enabled = false;
btnCancel.Enabled = true;
progressBar.Visible = true;
lblProgress.Text = "正在压缩...";
// 获取压缩设置
var settings = new ZipSettings
{
OutputPath = outputZipPath,
CompressionLevel = GetCompressionLevel(),
Password = txtPassword.Text,
IncludeBaseDirectory = chkIncludeBaseDir.Checked,
OverwriteExisting = chkOverwrite.Checked
};
// 开始压缩
zipManager.CompressFiles(selectedFiles, settings);
}
private System.IO.Compression.CompressionLevel GetCompressionLevel()
{
switch (cmbCompressionLevel.SelectedIndex)
{
case 0: return System.IO.Compression.CompressionLevel.NoCompression;
case 1: return System.IO.Compression.CompressionLevel.Fastest;
case 2: return System.IO.Compression.CompressionLevel.Optimal;
default: return System.IO.Compression.CompressionLevel.Optimal;
}
}
private void ZipManager_ProgressChanged(object sender, ProgressEventArgs e)
{
// 更新进度条
progressBar.Value = e.ProgressPercentage;
lblProgress.Text = $"正在压缩: {e.CurrentFile} ({e.ProgressPercentage}%)";
// 更新UI
Application.DoEvents();
}
private void ZipManager_OperationCompleted(object sender, OperationCompletedEventArgs e)
{
// 启用按钮
btnCompress.Enabled = true;
btnCancel.Enabled = false;
progressBar.Visible = false;
if (e.Success)
{
lblProgress.Text = $"压缩完成!输出文件: {e.OutputPath}";
MessageBox.Show($"压缩完成!\n输出文件: {e.OutputPath}\n压缩前大小: {FormatFileSize(e.OriginalSize)}\n压缩后大小: {FormatFileSize(e.CompressedSize)}\n压缩率: {e.CompressionRatio:P2}",
"完成", MessageBoxButtons.OK, MessageBoxIcon.Information);
}
else
{
lblProgress.Text = $"压缩失败: {e.ErrorMessage}";
MessageBox.Show($"压缩失败: {e.ErrorMessage}", "错误", MessageBoxButtons.OK, MessageBoxIcon.Error);
}
}
private void btnCancel_Click(object sender, EventArgs e)
{
zipManager.CancelOperation();
btnCancel.Enabled = false;
lblProgress.Text = "操作已取消";
}
private void btnExtract_Click(object sender, EventArgs e)
{
OpenFileDialog openFileDialog = new OpenFileDialog();
openFileDialog.Filter = "ZIP文件|*.zip|所有文件|*.*";
if (openFileDialog.ShowDialog() == DialogResult.OK)
{
FolderBrowserDialog folderDialog = new FolderBrowserDialog();
folderDialog.Description = "选择解压目标文件夹";
if (folderDialog.ShowDialog() == DialogResult.OK)
{
try
{
ZipExtractor extractor = new ZipExtractor();
extractor.ExtractZip(openFileDialog.FileName, folderDialog.SelectedPath, txtPassword.Text);
MessageBox.Show("解压完成!", "完成", MessageBoxButtons.OK, MessageBoxIcon.Information);
}
catch (Exception ex)
{
MessageBox.Show($"解压失败: {ex.Message}", "错误", MessageBoxButtons.OK, MessageBoxIcon.Error);
}
}
}
}
#region Windows Form Designer generated code
private System.ComponentModel.IContainer components = null;
private MenuStrip menuStrip1;
private ToolStripMenuItem 文件ToolStripMenuItem;
private ToolStripMenuItem 退出ToolStripMenuItem;
private ToolStripMenuItem 帮助ToolStripMenuItem;
private ToolStripMenuItem 关于ToolStripMenuItem;
private GroupBox groupBox1;
private Button btnSelectFiles;
private Button btnSelectFolder;
private ListBox lstFiles;
private Label lblFileCount;
private Label lblTotalSize;
private GroupBox groupBox2;
private TextBox txtOutputPath;
private Button btnSelectOutput;
private Label label1;
private ComboBox cmbCompressionLevel;
private Label label2;
private CheckBox chkIncludeBaseDir;
private CheckBox chkOverwrite;
private TextBox txtPassword;
private Label label3;
private GroupBox groupBox3;
private Button btnCompress;
private Button btnCancel;
private Button btnExtract;
private ProgressBar progressBar;
private Label lblProgress;
private void InitializeComponent()
{
this.components = new System.ComponentModel.Container();
this.menuStrip1 = new System.Windows.Forms.MenuStrip();
this.文件ToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
this.退出ToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
this.帮助ToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
this.关于ToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
this.groupBox1 = new System.Windows.Forms.GroupBox();
this.lblTotalSize = new System.Windows.Forms.Label();
this.lblFileCount = new System.Windows.Forms.Label();
this.lstFiles = new System.Windows.Forms.ListBox();
this.btnSelectFolder = new System.Windows.Forms.Button();
this.btnSelectFiles = new System.Windows.Forms.Button();
this.groupBox2 = new System.Windows.Forms.GroupBox();
this.txtPassword = new System.Windows.Forms.TextBox();
this.label3 = new System.Windows.Forms.Label();
this.chkOverwrite = new System.Windows.Forms.CheckBox();
this.chkIncludeBaseDir = new System.Windows.Forms.CheckBox();
this.label2 = new System.Windows.Forms.Label();
this.cmbCompressionLevel = new System.Windows.Forms.ComboBox();
this.label1 = new System.Windows.Forms.Label();
this.btnSelectOutput = new System.Windows.Forms.Button();
this.txtOutputPath = new System.Windows.Forms.TextBox();
this.groupBox3 = new System.Windows.Forms.GroupBox();
this.btnExtract = new System.Windows.Forms.Button();
this.btnCancel = new System.Windows.Forms.Button();
this.btnCompress = new System.Windows.Forms.Button();
this.progressBar = new System.Windows.Forms.ProgressBar();
this.lblProgress = new System.Windows.Forms.Label();
this.menuStrip1.SuspendLayout();
this.groupBox1.SuspendLayout();
this.groupBox2.SuspendLayout();
this.groupBox3.SuspendLayout();
this.SuspendLayout();
// menuStrip1
this.menuStrip1.Items.AddRange(new System.Windows.Forms.ToolStripItem[] {
this.文件ToolStripMenuItem,
this.帮助ToolStripMenuItem});
this.menuStrip1.Location = new System.Drawing.Point(0, 0);
this.menuStrip1.Name = "menuStrip1";
this.menuStrip1.Size = new System.Drawing.Size(700, 25);
this.menuStrip1.TabIndex = 0;
this.menuStrip1.Text = "menuStrip1";
// 文件ToolStripMenuItem
this.文件ToolStripMenuItem.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] {
this.退出ToolStripMenuItem});
this.文件ToolStripMenuItem.Name = "文件ToolStripMenuItem";
this.文件ToolStripMenuItem.Size = new System.Drawing.Size(44, 21);
this.文件ToolStripMenuItem.Text = "文件";
// 退出ToolStripMenuItem
this.退出ToolStripMenuItem.Name = "退出ToolStripMenuItem";
this.退出ToolStripMenuItem.Size = new System.Drawing.Size(93, 22);
this.退出ToolStripMenuItem.Text = "退出";
this.退出ToolStripMenuItem.Click += new System.EventHandler(this.退出ToolStripMenuItem_Click);
// 帮助ToolStripMenuItem
this.帮助ToolStripMenuItem.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] {
this.关于ToolStripMenuItem});
this.帮助ToolStripMenuItem.Name = "帮助ToolStripMenuItem";
this.帮助ToolStripMenuItem.Size = new System.Drawing.Size(44, 21);
this.帮助ToolStripMenuItem.Text = "帮助";
// 关于ToolStripMenuItem
this.关于ToolStripMenuItem.Name = "关于ToolStripMenuItem";
this.关于ToolStripMenuItem.Size = new System.Drawing.Size(107, 22);
this.关于ToolStripMenuItem.Text = "关于";
this.关于ToolStripMenuItem.Click += new System.EventHandler(this.关于ToolStripMenuItem_Click);
// groupBox1
this.groupBox1.Controls.Add(this.lblTotalSize);
this.groupBox1.Controls.Add(this.lblFileCount);
this.groupBox1.Controls.Add(this.lstFiles);
this.groupBox1.Controls.Add(this.btnSelectFolder);
this.groupBox1.Controls.Add(this.btnSelectFiles);
this.groupBox1.Location = new System.Drawing.Point(12, 30);
this.groupBox1.Name = "groupBox1";
this.groupBox1.Size = new System.Drawing.Size(300, 300);
this.groupBox1.TabIndex = 1;
this.groupBox1.TabStop = false;
this.groupBox1.Text = "选择文件";
// lblTotalSize
this.lblTotalSize.AutoSize = true;
this.lblTotalSize.Location = new System.Drawing.Point(20, 265);
this.lblTotalSize.Name = "lblTotalSize";
this.lblTotalSize.Size = new System.Drawing.Size(67, 13);
this.lblTotalSize.TabIndex = 4;
this.lblTotalSize.Text = "总大小: 0 KB";
// lblFileCount
this.lblFileCount.AutoSize = true;
this.lblFileCount.Location = new System.Drawing.Point(20, 245);
this.lblFileCount.Name = "lblFileCount";
this.lblFileCount.Size = new System.Drawing.Size(67, 13);
this.lblFileCount.TabIndex = 3;
this.lblFileCount.Text = "已选择 0 个文件";
// lstFiles
this.lstFiles.FormattingEnabled = true;
this.lstFiles.Location = new System.Drawing.Point(20, 25);
this.lstFiles.Name = "lstFiles";
this.lstFiles.Size = new System.Drawing.Size(260, 212);
this.lstFiles.TabIndex = 2;
// btnSelectFolder
this.btnSelectFolder.Location = new System.Drawing.Point(150, 275);
this.btnSelectFolder.Name = "btnSelectFolder";
this.btnSelectFolder.Size = new System.Drawing.Size(130, 25);
this.btnSelectFolder.TabIndex = 1;
this.btnSelectFolder.Text = "选择文件夹";
this.btnSelectFolder.UseVisualStyleBackColor = true;
this.btnSelectFolder.Click += new System.EventHandler(this.btnSelectFolder_Click);
// btnSelectFiles
this.btnSelectFiles.Location = new System.Drawing.Point(20, 275);
this.btnSelectFiles.Name = "btnSelectFiles";
this.btnSelectFiles.Size = new System.Drawing.Size(120, 25);
this.btnSelectFiles.TabIndex = 0;
this.btnSelectFiles.Text = "选择文件...";
this.btnSelectFiles.UseVisualStyleBackColor = true;
this.btnSelectFiles.Click += new System.EventHandler(this.btnSelectFiles_Click);
// groupBox2
this.groupBox2.Controls.Add(this.txtPassword);
this.groupBox2.Controls.Add(this.label3);
this.groupBox2.Controls.Add(this.chkOverwrite);
this.groupBox2.Controls.Add(this.chkIncludeBaseDir);
this.groupBox2.Controls.Add(this.label2);
this.groupBox2.Controls.Add(this.cmbCompressionLevel);
this.groupBox2.Controls.Add(this.label1);
this.groupBox2.Controls.Add(this.btnSelectOutput);
this.groupBox2.Controls.Add(this.txtOutputPath);
this.groupBox2.Location = new System.Drawing.Point(320, 30);
this.groupBox2.Name = "groupBox2";
this.groupBox2.Size = new System.Drawing.Size(350, 200);
this.groupBox2.TabIndex = 2;
this.groupBox2.TabStop = false;
this.groupBox2.Text = "压缩设置";
// txtPassword
this.txtPassword.Location = new System.Drawing.Point(100, 155);
this.txtPassword.Name = "txtPassword";
this.txtPassword.PasswordChar = '*';
this.txtPassword.Size = new System.Drawing.Size(230, 23);
this.txtPassword.TabIndex = 9;
// label3
this.label3.AutoSize = true;
this.label3.Location = new System.Drawing.Point(20, 158);
this.label3.Name = "label3";
this.label3.Size = new System.Drawing.Size(44, 13);
this.label3.TabIndex = 8;
this.label3.Text = "密码:";
// chkOverwrite
this.chkOverwrite.AutoSize = true;
this.chkOverwrite.Location = new System.Drawing.Point(20, 125);
this.chkOverwrite.Name = "chkOverwrite";
this.chkOverwrite.Size = new System.Drawing.Size(96, 17);
this.chkOverwrite.TabIndex = 7;
this.chkOverwrite.Text = "覆盖已有文件";
this.chkOverwrite.UseVisualStyleBackColor = true;
// chkIncludeBaseDir
this.chkIncludeBaseDir.AutoSize = true;
this.chkIncludeBaseDir.Location = new System.Drawing.Point(20, 100);
this.chkIncludeBaseDir.Name = "chkIncludeBaseDir";
this.chkIncludeBaseDir.Size = new System.Drawing.Size(120, 17);
this.chkIncludeBaseDir.TabIndex = 6;
this.chkIncludeBaseDir.Text = "包含基目录名称";
this.chkIncludeBaseDir.UseVisualStyleBackColor = true;
// label2
this.label2.AutoSize = true;
this.label2.Location = new System.Drawing.Point(20, 75);
this.label2.Name = "label2";
this.label2.Size = new System.Drawing.Size(56, 13);
this.label2.TabIndex = 5;
this.label2.Text = "压缩级别:";
// cmbCompressionLevel
this.cmbCompressionLevel.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList;
this.cmbCompressionLevel.FormattingEnabled = true;
this.cmbCompressionLevel.Items.AddRange(new object[] { "无压缩", "最快压缩", "最佳压缩" });
this.cmbCompressionLevel.Location = new System.Drawing.Point(100, 72);
this.cmbCompressionLevel.Name = "cmbCompressionLevel";
this.cmbCompressionLevel.Size = new System.Drawing.Size(230, 23);
this.cmbCompressionLevel.TabIndex = 4;
this.cmbCompressionLevel.SelectedIndex = 2;
// label1
this.label1.AutoSize = true;
this.label1.Location = new System.Drawing.Point(20, 45);
this.label1.Name = "label1";
this.label1.Size = new System.Drawing.Size(56, 13);
this.label1.TabIndex = 3;
this.label1.Text = "输出文件:";
// btnSelectOutput
this.btnSelectOutput.Location = new System.Drawing.Point(305, 40);
this.btnSelectOutput.Name = "btnSelectOutput";
this.btnSelectOutput.Size = new System.Drawing.Size(25, 23);
this.btnSelectOutput.TabIndex = 2;
this.btnSelectOutput.Text = "...";
this.btnSelectOutput.UseVisualStyleBackColor = true;
this.btnSelectOutput.Click += new System.EventHandler(this.btnSelectOutput_Click);
// txtOutputPath
this.txtOutputPath.Location = new System.Drawing.Point(100, 42);
this.txtOutputPath.Name = "txtOutputPath";
this.txtOutputPath.Size = new System.Drawing.Size(200, 23);
this.txtOutputPath.TabIndex = 1;
// groupBox3
this.groupBox3.Controls.Add(this.btnExtract);
this.groupBox3.Controls.Add(this.btnCancel);
this.groupBox3.Controls.Add(this.btnCompress);
this.groupBox3.Location = new System.Drawing.Point(320, 240);
this.groupBox3.Name = "groupBox3";
this.groupBox3.Size = new System.Drawing.Size(350, 90);
this.groupBox3.TabIndex = 3;
this.groupBox3.TabStop = false;
this.groupBox3.Text = "操作";
// btnExtract
this.btnExtract.Location = new System.Drawing.Point(240, 35);
this.btnExtract.Name = "btnExtract";
this.btnExtract.Size = new System.Drawing.Size(90, 25);
this.btnExtract.TabIndex = 2;
this.btnExtract.Text = "解压ZIP";
this.btnExtract.UseVisualStyleBackColor = true;
this.btnExtract.Click += new System.EventHandler(this.btnExtract_Click);
// btnCancel
this.btnCancel.Location = new System.Drawing.Point(130, 35);
this.btnCancel.Name = "btnCancel";
this.btnCancel.Size = new System.Drawing.Size(90, 25);
this.btnCancel.TabIndex = 1;
this.btnCancel.Text = "取消";
this.btnCancel.UseVisualStyleBackColor = true;
this.btnCancel.Click += new System.EventHandler(this.btnCancel_Click);
this.btnCancel.Enabled = false;
// btnCompress
this.btnCompress.Location = new System.Drawing.Point(20, 35);
this.btnCompress.Name = "btnCompress";
this.btnCompress.Size = new System.Drawing.Size(90, 25);
this.btnCompress.TabIndex = 0;
this.btnCompress.Text = "压缩";
this.btnCompress.UseVisualStyleBackColor = true;
this.btnCompress.Click += new System.EventHandler(this.btnCompress_Click);
// progressBar
this.progressBar.Location = new System.Drawing.Point(12, 340);
this.progressBar.Name = "progressBar";
this.progressBar.Size = new System.Drawing.Size(658, 23);
this.progressBar.TabIndex = 4;
this.progressBar.Visible = false;
// lblProgress
this.lblProgress.AutoSize = true;
this.lblProgress.Location = new System.Drawing.Point(12, 370);
this.lblProgress.Name = "lblProgress";
this.lblProgress.Size = new System.Drawing.Size(44, 13);
this.lblProgress.TabIndex = 5;
this.lblProgress.Text = "就绪...";
// MainForm
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.ClientSize = new System.Drawing.Size(682, 392);
this.Controls.Add(this.lblProgress);
this.Controls.Add(this.progressBar);
this.Controls.Add(this.groupBox3);
this.Controls.Add(this.groupBox2);
this.Controls.Add(this.groupBox1);
this.Controls.Add(this.menuStrip1);
this.MainMenuStrip = this.menuStrip1;
this.Name = "MainForm";
this.Text = "文件压缩工具 - ZIP打包";
this.menuStrip1.ResumeLayout(false);
this.menuStrip1.PerformLayout();
this.groupBox1.ResumeLayout(false);
this.groupBox1.PerformLayout();
this.groupBox2.ResumeLayout(false);
this.groupBox2.PerformLayout();
this.groupBox3.ResumeLayout(false);
this.ResumeLayout(false);
this.PerformLayout();
}
private void 退出ToolStripMenuItem_Click(object sender, EventArgs e)
{
Application.Exit();
}
private void 关于ToolStripMenuItem_Click(object sender, EventArgs e)
{
MessageBox.Show("文件压缩工具 v1.0\n\n支持将多个文件打包成ZIP压缩包\n© 2024 版权所有", "关于", MessageBoxButtons.OK, MessageBoxIcon.Information);
}
#endregion
}
}
2.4 ZIP压缩管理器 (ZipManager.cs)
using System;
using System.Collections.Generic;
using System.IO;
using System.IO.Compression;
using System.Threading;
using System.Threading.Tasks;
namespace FileCompressor
{
/// <summary>
/// ZIP压缩管理器
/// </summary>
public class ZipManager
{
private CancellationTokenSource cancellationTokenSource;
private bool isOperationCancelled = false;
// 事件
public event EventHandler<ProgressEventArgs> ProgressChanged;
public event EventHandler<OperationCompletedEventArgs> OperationCompleted;
/// <summary>
/// 压缩多个文件到一个ZIP文件
/// </summary>
public async void CompressFiles(List<string> filePaths, ZipSettings settings)
{
cancellationTokenSource = new CancellationTokenSource();
isOperationCancelled = false;
try
{
// 检查输出文件是否已存在
if (File.Exists(settings.OutputPath) && !settings.OverwriteExisting)
{
OnOperationCompleted(false, settings.OutputPath, 0, 0, "输出文件已存在");
return;
}
// 确保输出目录存在
string outputDir = Path.GetDirectoryName(settings.OutputPath);
if (!string.IsNullOrEmpty(outputDir) && !Directory.Exists(outputDir))
{
Directory.CreateDirectory(outputDir);
}
// 计算总大小
long totalSize = CalculateTotalSize(filePaths);
long compressedSize = 0;
int fileCount = filePaths.Count;
int processedCount = 0;
// 使用异步压缩
await Task.Run(() =>
{
using (FileStream zipFileStream = new FileStream(settings.OutputPath, FileMode.Create))
using (ZipArchive archive = new ZipArchive(zipFileStream, ZipArchiveMode.Create, true))
{
foreach (string filePath in filePaths)
{
if (isOperationCancelled)
break;
if (File.Exists(filePath))
{
try
{
// 获取相对路径
string entryName = GetEntryName(filePath, settings.IncludeBaseDirectory);
// 创建ZIP条目
ZipArchiveEntry entry = archive.CreateEntry(entryName, settings.CompressionLevel);
// 写入文件内容
using (FileStream originalFileStream = new FileStream(filePath, FileMode.Open, FileAccess.Read))
using (Stream entryStream = entry.Open())
{
byte[] buffer = new byte[4096];
int bytesRead;
long fileSize = originalFileStream.Length;
long copiedBytes = 0;
while ((bytesRead = originalFileStream.Read(buffer, 0, buffer.Length)) > 0)
{
if (isOperationCancelled)
break;
entryStream.Write(buffer, 0, bytesRead);
copiedBytes += bytesRead;
compressedSize += bytesRead;
// 更新进度
int progress = (int)((double)compressedSize / totalSize * 100);
OnProgressChanged(progress, Path.GetFileName(filePath));
}
}
processedCount++;
}
catch (Exception ex)
{
throw new Exception($"压缩文件 {filePath} 失败: {ex.Message}");
}
}
else if (Directory.Exists(filePath))
{
// 压缩文件夹
CompressDirectory(filePath, archive, settings, ref compressedSize, totalSize);
processedCount++;
}
}
}
}, cancellationTokenSource.Token);
if (!isOperationCancelled)
{
// 获取压缩后文件大小
FileInfo zipFileInfo = new FileInfo(settings.OutputPath);
long finalCompressedSize = zipFileInfo.Length;
OnOperationCompleted(true, settings.OutputPath, totalSize, finalCompressedSize, "压缩完成");
}
}
catch (OperationCanceledException)
{
OnOperationCompleted(false, settings.OutputPath, 0, 0, "操作已取消");
}
catch (Exception ex)
{
OnOperationCompleted(false, settings.OutputPath, 0, 0, ex.Message);
}
}
/// <summary>
/// 压缩文件夹
/// </summary>
private void CompressDirectory(string folderPath, ZipArchive archive, ZipSettings settings, ref long compressedSize, long totalSize)
{
string baseFolderName = settings.IncludeBaseDirectory ? Path.GetFileName(folderPath) : "";
foreach (string filePath in Directory.GetFiles(folderPath, "*", SearchOption.AllDirectories))
{
if (isOperationCancelled)
break;
try
{
string relativePath = GetRelativePath(folderPath, filePath);
if (!string.IsNullOrEmpty(baseFolderName))
{
relativePath = Path.Combine(baseFolderName, relativePath);
}
ZipArchiveEntry entry = archive.CreateEntry(relativePath, settings.CompressionLevel);
using (FileStream originalFileStream = new FileStream(filePath, FileMode.Open, FileAccess.Read))
using (Stream entryStream = entry.Open())
{
byte[] buffer = new byte[4096];
int bytesRead;
while ((bytesRead = originalFileStream.Read(buffer, 0, buffer.Length)) > 0)
{
if (isOperationCancelled)
break;
entryStream.Write(buffer, 0, bytesRead);
compressedSize += bytesRead;
// 更新进度
int progress = (int)((double)compressedSize / totalSize * 100);
OnProgressChanged(progress, Path.GetFileName(filePath));
}
}
}
catch (Exception ex)
{
throw new Exception($"压缩文件夹 {filePath} 失败: {ex.Message}");
}
}
}
/// <summary>
/// 计算总大小
/// </summary>
private long CalculateTotalSize(List<string> filePaths)
{
long totalSize = 0;
foreach (string path in filePaths)
{
if (File.Exists(path))
{
totalSize += new FileInfo(path).Length;
}
else if (Directory.Exists(path))
{
totalSize += CalculateDirectorySize(path);
}
}
return totalSize;
}
/// <summary>
/// 计算文件夹大小
/// </summary>
private long CalculateDirectorySize(string folderPath)
{
long size = 0;
foreach (string file in Directory.GetFiles(folderPath, "*", SearchOption.AllDirectories))
{
if (File.Exists(file))
{
size += new FileInfo(file).Length;
}
}
return size;
}
/// <summary>
/// 获取ZIP条目名称
/// </summary>
private string GetEntryName(string filePath, bool includeBaseDirectory)
{
if (includeBaseDirectory)
{
return Path.GetFileName(filePath);
}
else
{
return Path.GetFileName(filePath);
}
}
/// <summary>
/// 获取相对路径
/// </summary>
private string GetRelativePath(string basePath, string fullPath)
{
Uri baseUri = new Uri(basePath.EndsWith("\\") ? basePath : basePath + "\\");
Uri fullUri = new Uri(fullPath);
return Uri.UnescapeDataString(baseUri.MakeRelativeUri(fullUri).ToString().Replace('/', Path.DirectorySeparatorChar));
}
/// <summary>
/// 取消操作
/// </summary>
public void CancelOperation()
{
isOperationCancelled = true;
cancellationTokenSource?.Cancel();
}
/// <summary>
/// 触发进度变化事件
/// </summary>
protected virtual void OnProgressChanged(int progress, string currentFile)
{
ProgressChanged?.Invoke(this, new ProgressEventArgs(progress, currentFile));
}
/// <summary>
/// 触发操作完成事件
/// </summary>
protected virtual void OnOperationCompleted(bool success, string outputPath, long originalSize, long compressedSize, string message)
{
OperationCompleted?.Invoke(this, new OperationCompletedEventArgs(success, outputPath, originalSize, compressedSize, message));
}
}
/// <summary>
/// ZIP压缩设置
/// </summary>
public class ZipSettings
{
public string OutputPath { get; set; } = "";
public CompressionLevel CompressionLevel { get; set; } = CompressionLevel.Optimal;
public string Password { get; set; } = "";
public bool IncludeBaseDirectory { get; set; } = false;
public bool OverwriteExisting { get; set; } = false;
}
/// <summary>
/// 进度事件参数
/// </summary>
public class ProgressEventArgs : EventArgs
{
public int ProgressPercentage { get; set; }
public string CurrentFile { get; set; }
public ProgressEventArgs(int progress, string currentFile)
{
ProgressPercentage = progress;
CurrentFile = currentFile;
}
}
/// <summary>
/// 操作完成事件参数
/// </summary>
public class OperationCompletedEventArgs : EventArgs
{
public bool Success { get; set; }
public string OutputPath { get; set; }
public long OriginalSize { get; set; }
public long CompressedSize { get; set; }
public string ErrorMessage { get; set; }
public double CompressionRatio => OriginalSize > 0 ? 1.0 - (double)CompressedSize / OriginalSize : 0;
public OperationCompletedEventArgs(bool success, string outputPath, long originalSize, long compressedSize, string errorMessage)
{
Success = success;
OutputPath = outputPath;
OriginalSize = originalSize;
CompressedSize = compressedSize;
ErrorMessage = errorMessage;
}
}
}
2.5 文件选择器 (FileSelector.cs)
using System;
using System.Collections.Generic;
using System.IO;
using System.Windows.Forms;
namespace FileCompressor
{
/// <summary>
/// 文件选择器
/// </summary>
public class FileSelector
{
/// <summary>
/// 选择多个文件
/// </summary>
public List<string> SelectFiles()
{
OpenFileDialog openFileDialog = new OpenFileDialog();
openFileDialog.Multiselect = true;
openFileDialog.Filter = "所有文件|*.*|文本文件|*.txt|图片文件|*.jpg;*.png;*.gif;*.bmp|文档文件|*.doc;*.docx;*.pdf";
openFileDialog.Title = "选择要压缩的文件";
if (openFileDialog.ShowDialog() == DialogResult.OK)
{
return new List<string>(openFileDialog.FileNames);
}
return new List<string>();
}
/// <summary>
/// 选择文件夹
/// </summary>
public List<string> SelectFolder()
{
FolderBrowserDialog folderDialog = new FolderBrowserDialog();
folderDialog.Description = "选择要压缩的文件夹";
folderDialog.ShowNewFolderButton = false;
if (folderDialog.ShowDialog() == DialogResult.OK)
{
return new List<string> { folderDialog.SelectedPath };
}
return new List<string>();
}
/// <summary>
/// 选择多个文件夹
/// </summary>
public List<string> SelectMultipleFolders()
{
List<string> folders = new List<string>();
while (true)
{
FolderBrowserDialog folderDialog = new FolderBrowserDialog();
folderDialog.Description = "选择要压缩的文件夹(点击取消结束选择)";
folderDialog.ShowNewFolderButton = false;
if (folderDialog.ShowDialog() == DialogResult.OK)
{
folders.Add(folderDialog.SelectedPath);
DialogResult result = MessageBox.Show("是否继续选择其他文件夹?", "选择文件夹", MessageBoxButtons.YesNo, MessageBoxIcon.Question);
if (result == DialogResult.No)
break;
}
else
{
break;
}
}
return folders;
}
}
}
2.6 ZIP解压管理器 (ZipExtractor.cs)
using System;
using System.IO;
using System.IO.Compression;
namespace FileCompressor
{
/// <summary>
/// ZIP解压管理器
/// </summary>
public class ZipExtractor
{
/// <summary>
/// 解压ZIP文件
/// </summary>
public void ExtractZip(string zipPath, string extractPath, string password = "")
{
try
{
// 确保解压目录存在
if (!Directory.Exists(extractPath))
{
Directory.CreateDirectory(extractPath);
}
// 使用 .NET 内置的 ZIP 解压功能
ZipFile.ExtractToDirectory(zipPath, extractPath, true);
}
catch (Exception ex)
{
throw new Exception($"解压失败: {ex.Message}", ex);
}
}
/// <summary>
/// 解压ZIP文件中的特定文件
/// </summary>
public void ExtractSpecificFiles(string zipPath, string extractPath, string[] filePatterns)
{
try
{
if (!Directory.Exists(extractPath))
{
Directory.CreateDirectory(extractPath);
}
using (ZipArchive archive = ZipFile.OpenRead(zipPath))
{
foreach (string pattern in filePatterns)
{
var entries = archive.Entries.Where(e => e.Name.Contains(pattern, StringComparison.OrdinalIgnoreCase));
foreach (var entry in entries)
{
string destinationPath = Path.Combine(extractPath, entry.Name);
entry.ExtractToFile(destinationPath, true);
}
}
}
}
catch (Exception ex)
{
throw new Exception($"解压特定文件失败: {ex.Message}", ex);
}
}
/// <summary>
/// 获取ZIP文件中的文件列表
/// </summary>
public string[] GetFileList(string zipPath)
{
try
{
using (ZipArchive archive = ZipFile.OpenRead(zipPath))
{
string[] files = new string[archive.Entries.Count];
for (int i = 0; i < archive.Entries.Count; i++)
{
files[i] = archive.Entries[i].FullName;
}
return files;
}
}
catch (Exception ex)
{
throw new Exception($"获取文件列表失败: {ex.Message}", ex);
}
}
/// <summary>
/// 检查ZIP文件是否有效
/// </summary>
public bool IsValidZipFile(string zipPath)
{
try
{
using (ZipArchive archive = ZipFile.OpenRead(zipPath))
{
return true;
}
}
catch
{
return false;
}
}
}
}
2.7 使用 SharpZipLib 的增强版本(支持密码保护)
// 如果需要更强的密码保护和更多功能,可以使用 SharpZipLib
using ICSharpCode.SharpZipLib.Zip;
using ICSharpCode.SharpZipLib.Core;
namespace FileCompressor
{
/// <summary>
/// 使用 SharpZipLib 的 ZIP 压缩管理器(支持密码保护)
/// </summary>
public class AdvancedZipManager
{
/// <summary>
/// 压缩文件(支持密码)
/// </summary>
public void CompressFilesWithPassword(List<string> filePaths, string outputPath, string password, int compressionLevel = 3)
{
try
{
using (FileStream fsOut = File.Create(outputPath))
using (ZipOutputStream zipStream = new ZipOutputStream(fsOut))
{
// 设置密码
if (!string.IsNullOrEmpty(password))
{
zipStream.Password = password;
}
// 设置压缩级别 (0-9)
zipStream.SetLevel(compressionLevel);
foreach (string filePath in filePaths)
{
if (File.Exists(filePath))
{
CompressFile(filePath, zipStream);
}
else if (Directory.Exists(filePath))
{
CompressDirectory(filePath, zipStream, Path.GetFileName(filePath));
}
}
}
}
catch (Exception ex)
{
throw new Exception($"压缩失败: {ex.Message}", ex);
}
}
private void CompressFile(string filePath, ZipOutputStream zipStream)
{
FileInfo fi = new FileInfo(filePath);
string entryName = fi.Name;
ZipEntry newEntry = new ZipEntry(entryName);
newEntry.DateTime = fi.LastWriteTime;
newEntry.Size = fi.Length;
zipStream.PutNextEntry(newEntry);
byte[] buffer = new byte[4096];
using (FileStream fsInput = File.OpenRead(filePath))
{
StreamUtils.Copy(fsInput, zipStream, buffer);
}
zipStream.CloseEntry();
}
private void CompressDirectory(string folderPath, ZipOutputStream zipStream, string baseFolderName)
{
string[] files = Directory.GetFiles(folderPath, "*", SearchOption.AllDirectories);
foreach (string filePath in files)
{
string relativePath = filePath.Substring(folderPath.Length + 1);
string entryName = Path.Combine(baseFolderName, relativePath).Replace("\\", "/");
FileInfo fi = new FileInfo(filePath);
ZipEntry newEntry = new ZipEntry(entryName);
newEntry.DateTime = fi.LastWriteTime;
newEntry.Size = fi.Length;
zipStream.PutNextEntry(newEntry);
byte[] buffer = new byte[4096];
using (FileStream fsInput = File.OpenRead(filePath))
{
StreamUtils.Copy(fsInput, zipStream, buffer);
}
zipStream.CloseEntry();
}
}
/// <summary>
/// 解压文件(支持密码)
/// </summary>
public void ExtractFilesWithPassword(string zipPath, string extractPath, string password)
{
try
{
if (!Directory.Exists(extractPath))
{
Directory.CreateDirectory(extractPath);
}
using (FileStream fsIn = File.OpenRead(zipPath))
using (ZipInputStream zipStream = new ZipInputStream(fsIn))
{
// 设置密码
if (!string.IsNullOrEmpty(password))
{
zipStream.Password = password;
}
ZipEntry entry;
while ((entry = zipStream.GetNextEntry()) != null)
{
string outputFile = Path.Combine(extractPath, entry.Name);
string outputDir = Path.GetDirectoryName(outputFile);
if (!Directory.Exists(outputDir))
{
Directory.CreateDirectory(outputDir);
}
if (!entry.IsDirectory)
{
using (FileStream fsOut = File.Create(outputFile))
{
byte[] buffer = new byte[4096];
int bytesRead;
while ((bytesRead = zipStream.Read(buffer, 0, buffer.Length)) > 0)
{
fsOut.Write(buffer, 0, bytesRead);
}
}
}
}
}
}
catch (Exception ex)
{
throw new Exception($"解压失败: {ex.Message}", ex);
}
}
}
}
参考代码 C# 将多个文件打包压缩成一个ZIP文件包 www.youwenfan.com/contentcnv/116275.html
三、功能特点
多文件打包:支持将多个文件和文件夹打包成一个ZIP文件
密码保护:支持为ZIP文件设置密码(使用 SharpZipLib)
压缩级别控制:无压缩、最快压缩、最佳压缩三种级别
进度监控:实时显示压缩进度和当前处理的文件
取消操作:支持中途取消压缩操作
文件夹压缩:支持压缩整个文件夹及其子文件夹
解压功能:支持解压ZIP文件到指定目录
文件过滤:支持按文件类型筛选要压缩的文件
覆盖控制:可选择是否覆盖已存在的输出文件
四、使用说明
4.1 基本使用
- 运行程序,点击"选择文件"或"选择文件夹"添加要压缩的内容
- 设置输出文件路径和压缩选项
- 点击"压缩"按钮开始压缩
4.2 高级功能
- 密码保护:在密码框中输入密码,生成的ZIP文件将需要密码才能解压
- 包含基目录:勾选此项将在ZIP中保留文件夹结构
- 覆盖已有文件:勾选此项将覆盖同名的输出文件
4.3 批量操作
- 可以同时选择多个文件和文件夹进行压缩
- 支持拖拽文件到程序窗口(需要扩展代码)
4.4 注意事项
- 使用 .NET 内置的
ZipFile类不支持密码保护 - 如果需要密码保护,请使用 SharpZipLib 版本
- 大文件压缩可能需要较长时间,请耐心等待
浙公网安备 33010602011771号