C#壓縮解壓文件的常用方法
引言
在C#中處理文件和文件夾的壓縮與解壓,我們可使用微軟內(nèi)置的 System.IO.Compression 命名空間,也可選擇功能更豐富的第三方庫(kù)如 SharpZipLib。下面我將分別介紹幾種常見方法,并提供處理多文件夾和文件混合壓縮的方案。
1. 使用 .NET 內(nèi)置的 ZipFile 類
.NET Framework 4.5 及以上版本和 .NET Core/.NET 5+ 提供了 ZipFile 類,適用于簡(jiǎn)單的壓縮和解壓場(chǎng)景。
壓縮單個(gè)文件夾
using System.IO.Compression;
public static void CompressDirectory(string sourceDirectoryName, string destinationArchiveFileName)
{
ZipFile.CreateFromDirectory(sourceDirectoryName, destinationArchiveFileName, CompressionLevel.Optimal, false);
}
值得注意的是,使用ZipFile創(chuàng)建壓縮包,默認(rèn)不會(huì)包含根目錄。如果需要包含根目錄,可以先將文件夾復(fù)制到一個(gè)臨時(shí)目錄,然后壓縮該臨時(shí)目錄。
例如,我對(duì)一個(gè)名為“Build a Large Language Model”的目錄進(jìn)行壓縮,它里面包含了“doc”和“src”兩個(gè)目錄,壓縮后的效果如下圖:

解壓整個(gè)壓縮包
public static void ExtractArchive(string sourceArchiveFileName, string destinationDirectoryName)
{
ZipFile.ExtractToDirectory(sourceArchiveFileName, destinationDirectoryName);
}
壓縮單個(gè)文件
壓縮單個(gè)文件需要先創(chuàng)建臨時(shí)目錄,將文件復(fù)制進(jìn)去后再壓縮。
public static void CompressFile(string sourceFileName, string destinationArchiveFileName)
{
string tempDir = Path.Combine(Path.GetTempPath(), Path.GetRandomFileName());
Directory.CreateDirectory(tempDir);
try
{
string destFile = Path.Combine(tempDir, Path.GetFileName(sourceFileName));
File.Copy(sourceFileName, destFile);
ZipFile.CreateFromDirectory(tempDir, destinationArchiveFileName, CompressionLevel.Optimal, false);
}
finally
{
Directory.Delete(tempDir, true);
}
}
2. 使用 ZipArchive 進(jìn)行靈活操作
ZipArchive 類提供了更精細(xì)的控制,適合混合壓縮多個(gè)文件和文件夾。
壓縮多個(gè)文件和文件夾
此方法遞歸地添加文件和文件夾,保持目錄結(jié)構(gòu)。
using System.IO.Compression;
/// <summary>
/// 壓縮文件和文件夾到一個(gè)ZIP文件中
/// </summary>
/// <param name="zipPath">生成的壓縮包路徑</param>
/// <param name="filesToZip">需要壓縮的文件</param>
/// <param name="foldersToZip">需要壓縮的文件夾,默認(rèn)沒(méi)有</param>
public static void CreateZipFile(string zipPath, string[]? filesToZip, string[]? foldersToZip = null,
CompressionLevel compressionLevel = CompressionLevel.Optimal)
{
using (FileStream zipStream = new FileStream(zipPath, FileMode.Create))
using (ZipArchive archive = new ZipArchive(zipStream, ZipArchiveMode.Create))
{
// 添加單個(gè)文件
if (filesToZip != null)
{
foreach (string file in filesToZip)
{
if (File.Exists(file))
{
string entryName = Path.GetFileName(file);
archive.CreateEntryFromFile(file, entryName);
}
}
}
// 添加文件夾(遞歸)
if (foldersToZip != null)
{
foreach (string folder in foldersToZip)
{
if (Directory.Exists(folder))
{
AddFolderToZip(archive, folder, Path.GetFileName(folder), compressionLevel);
}
}
}
}
}
/// <summary>
/// 添加文件夾到ZIP歸檔中(遞歸)
/// </summary>
/// <param name="archive">ZIP壓縮包</param>
/// <param name="folderPath">文件夾路徑</param>
/// <param name="relativePath">相對(duì)路徑</param>
private static void AddFolderToZip(ZipArchive archive, string folderPath, string relativePath,
CompressionLevel compressionLevel)
{
string[] files = Directory.GetFiles(folderPath);
foreach (string file in files)
{
string entryName = Path.Combine(relativePath, Path.GetFileName(file));
archive.CreateEntryFromFile(file, entryName);
}
string[] subfolders = Directory.GetDirectories(folderPath);
foreach (string subfolder in subfolders)
{
string newRelativePath = Path.Combine(relativePath, Path.GetFileName(subfolder));
AddFolderToZip(archive, subfolder, newRelativePath, compressionLevel);
}
}
解壓(保留目錄結(jié)構(gòu))
public static void ExtractZipFile(string zipPath, string extractPath)
{
using (ZipArchive archive = ZipFile.OpenRead(zipPath))
{
foreach (ZipArchiveEntry entry in archive.Entries)
{
string fullPath = Path.Combine(extractPath, entry.FullName);
string directory = Path.GetDirectoryName(fullPath);
if (!Directory.Exists(directory))
Directory.CreateDirectory(directory);
if (!string.IsNullOrEmpty(entry.Name))
entry.ExtractToFile(fullPath, overwrite: true);
}
}
}
3. 使用 SharpZipLib 庫(kù)
對(duì)于更高級(jí)的需求(如加密、壓縮級(jí)別控制、Unicode支持),可使用 SharpZipLib。
安裝 SharpZipLib
通過(guò) NuGet 包管理器安裝:
Install-Package SharpZipLib
壓縮多個(gè)文件和文件夾
using ICSharpCode.SharpZipLib.Zip;
public static void CreateZipWithSharpZipLib(string zipPath, string[] files, string[] folders, string password = null)
{
using (ZipOutputStream zipStream = new ZipOutputStream(File.Create(zipPath)))
{
zipStream.SetLevel(9); // 壓縮級(jí)別 (0-9)
if (!string.IsNullOrEmpty(password))
zipStream.Password = password;
byte[] buffer = new byte[4096];
// 添加文件
foreach (string file in files)
{
if (File.Exists(file))
{
ZipEntry entry = new ZipEntry(Path.GetFileName(file));
entry.DateTime = DateTime.Now;
zipStream.PutNextEntry(entry);
using (FileStream fs = File.OpenRead(file))
{
int sourceBytes;
while ((sourceBytes = fs.Read(buffer, 0, buffer.Length)) > 0)
{
zipStream.Write(buffer, 0, sourceBytes);
}
}
zipStream.CloseEntry();
}
}
// 添加文件夾
foreach (string folder in folders)
{
if (Directory.Exists(folder))
{
AddFolderToSharpZip(zipStream, folder, "", buffer);
}
}
zipStream.Finish();
}
}
private static void AddFolderToSharpZip(ZipOutputStream zipStream, string folderPath, string relativePath, byte[] buffer)
{
string[] files = Directory.GetFiles(folderPath);
foreach (string file in files)
{
string entryName = Path.Combine(relativePath, Path.GetFileName(file));
ZipEntry entry = new ZipEntry(entryName);
entry.DateTime = DateTime.Now;
zipStream.PutNextEntry(entry);
using (FileStream fs = File.OpenRead(file))
{
int sourceBytes;
while ((sourceBytes = fs.Read(buffer, 0, buffer.Length)) > 0)
{
zipStream.Write(buffer, 0, sourceBytes);
}
}
zipStream.CloseEntry();
}
string[] subfolders = Directory.GetDirectories(folderPath);
foreach (string subfolder in subfolders)
{
string newRelativePath = Path.Combine(relativePath, Path.GetFileName(subfolder));
AddFolderToSharpZip(zipStream, subfolder, newRelativePath, buffer);
}
}
使用 SharpZipLib 解壓
public static void ExtractWithSharpZipLib(string zipPath, string extractPath, string password = null)
{
using (ZipInputStream zipStream = new ZipInputStream(File.OpenRead(zipPath)))
{
zipStream.Password = password;
ZipEntry entry;
while ((entry = zipStream.GetNextEntry()) != null)
{
string fullPath = Path.Combine(extractPath, entry.Name);
string directory = Path.GetDirectoryName(fullPath);
if (!Directory.Exists(directory))
Directory.CreateDirectory(directory);
if (!string.IsNullOrEmpty(entry.Name))
{
using (FileStream streamWriter = File.Create(fullPath))
{
byte[] data = new byte[4096];
int size;
while ((size = zipStream.Read(data, 0, data.Length)) > 0)
{
streamWriter.Write(data, 0, size);
}
}
}
}
}
}
4. 錯(cuò)誤處理與最佳實(shí)踐
進(jìn)行壓縮和解壓操作時(shí),務(wù)必添加錯(cuò)誤處理。
try
{
// 你的壓縮或解壓代碼
}
catch (FileNotFoundException ex)
{
Console.WriteLine($"文件未找到: {ex.Message}");
}
catch (DirectoryNotFoundException ex)
{
Console.WriteLine($"目錄未找到: {ex.Message}");
}
catch (IOException ex)
{
Console.WriteLine($"IO錯(cuò)誤: {ex.Message}");
}
catch (UnauthorizedAccessException ex)
{
Console.WriteLine($"權(quán)限錯(cuò)誤: {ex.Message}");
}
catch (Exception ex)
{
Console.WriteLine($"未知錯(cuò)誤: {ex.Message}");
}
5. 方法對(duì)比與選擇
我們可以根據(jù)需求選擇合適的方法:
| 方法特性 | ZipFile (內(nèi)置) | ZipArchive (內(nèi)置) | SharpZipLib (第三方) |
|---|---|---|---|
| 易用性 | 高 | 中 | 中 |
| 功能豐富度 | 基礎(chǔ) | 中等 | 高(加密、Unicode支持等) |
| 性能 | 良好 | 良好 | 良好 |
| 無(wú)需額外依賴 | 是 | 是 | 否 |
| 跨平臺(tái)兼容性 | 是 | 是 | 是 |
| 推薦場(chǎng)景 | 簡(jiǎn)單壓縮/解壓 | 需精細(xì)控制 | 復(fù)雜需求(如加密) |
總結(jié)
在C#中實(shí)現(xiàn)zip壓縮和解壓,我們可根據(jù)需求選擇:
- 簡(jiǎn)單場(chǎng)景:使用內(nèi)置的
ZipFile類(ZipFile.CreateFromDirectory和ZipFile.ExtractToDirectory)最方便。 - 需精細(xì)控制或多文件/文件夾混合:使用
ZipArchive類逐項(xiàng)添加內(nèi)容更靈活。 - 有高級(jí)需求(如加密、更高壓縮比):
SharpZipLib等第三方庫(kù)功能更強(qiáng)大。
處理多文件和文件夾時(shí),遞歸添加是保持目錄結(jié)構(gòu)的關(guān)鍵。無(wú)論用哪種方法,都請(qǐng)注意添加適當(dāng)?shù)腻e(cuò)誤處理(如 try-catch 塊)以確保程序健壯性。
到此這篇關(guān)于C#壓縮解壓文件的常用方法的文章就介紹到這了,更多相關(guān)C#壓縮解壓文件內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
C#實(shí)現(xiàn)異步連接Sql Server數(shù)據(jù)庫(kù)的方法
這篇文章主要介紹了C#實(shí)現(xiàn)異步連接Sql Server數(shù)據(jù)庫(kù)的方法,涉及C#中await方法的相關(guān)使用技巧,具有一定參考借鑒價(jià)值,需要的朋友可以參考下2015-04-04
C#實(shí)現(xiàn)json的序列化和反序列化實(shí)例代碼
這篇文章主要介紹了C#實(shí)現(xiàn)json的序列化和反序列化實(shí)例代碼,有需要的朋友可以參考一下2013-12-12
Treeview動(dòng)態(tài)添加用戶控件傳值和取值的實(shí)例代碼
今天做了很好玩的樹,是treeview與用戶控件之間進(jìn)行交互先看效果:2013-04-04
C# byte數(shù)組與Image相互轉(zhuǎn)換的方法
這篇文章介紹了C# byte數(shù)組與Image相互轉(zhuǎn)換的方法,有需要的朋友可以參考一下2013-10-10
給c#添加SetTimeout和SetInterval函數(shù)
Javascript中的SetTimeout和SetInterval函數(shù)很方便,把他們移植到c#中來(lái)。2008-03-03

