引言
在c#中处理文件和文件夹的压缩与解压,我们可使用微软内置的 system.io.compression
命名空间,也可选择功能更丰富的第三方库如 sharpziplib
。下面我将分别介绍几种常见方法,并提供处理多文件夹和文件混合压缩的方案。
1. 使用 .net 内置的 zipfile 类
.net framework 4.5 及以上版本和 .net core/.net 5+ 提供了 zipfile
类,适用于简单的压缩和解压场景。
压缩单个文件夹
using system.io.compression; public static void compressdirectory(string sourcedirectoryname, string destinationarchivefilename) { zipfile.createfromdirectory(sourcedirectoryname, destinationarchivefilename, compressionlevel.optimal, false); }
值得注意的是,使用zipfile
创建压缩包,默认不会包含根目录。如果需要包含根目录,可以先将文件夹复制到一个临时目录,然后压缩该临时目录。
例如,我对一个名为“build a large language model”的目录进行压缩,它里面包含了“doc”和“src”两个目录,压缩后的效果如下图:
解压整个压缩包
public static void extractarchive(string sourcearchivefilename, string destinationdirectoryname) { zipfile.extracttodirectory(sourcearchivefilename, destinationdirectoryname); }
压缩单个文件
压缩单个文件需要先创建临时目录,将文件复制进去后再压缩。
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 进行灵活操作
ziparchive
类提供了更精细的控制,适合混合压缩多个文件和文件夹。
压缩多个文件和文件夹
此方法递归地添加文件和文件夹,保持目录结构。
using system.io.compression; /// <summary> /// 压缩文件和文件夹到一个zip文件中 /// </summary> /// <param name="zippath">生成的压缩包路径</param> /// <param name="filestozip">需要压缩的文件</param> /// <param name="folderstozip">需要压缩的文件夹,默认没有</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)) { // 添加单个文件 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">相对路径</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); } }
解压(保留目录结构)
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 库
对于更高级的需求(如加密、压缩级别控制、unicode支持),可使用 sharpziplib
。
安装 sharpziplib
通过 nuget 包管理器安装:
install-package sharpziplib
压缩多个文件和文件夹
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); // 压缩级别 (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. 错误处理与最佳实践
进行压缩和解压操作时,务必添加错误处理。
try { // 你的压缩或解压代码 } catch (filenotfoundexception ex) { console.writeline($"文件未找到: {ex.message}"); } catch (directorynotfoundexception ex) { console.writeline($"目录未找到: {ex.message}"); } catch (ioexception ex) { console.writeline($"io错误: {ex.message}"); } catch (unauthorizedaccessexception ex) { console.writeline($"权限错误: {ex.message}"); } catch (exception ex) { console.writeline($"未知错误: {ex.message}"); }
5. 方法对比与选择
我们可以根据需求选择合适的方法:
方法特性 | zipfile (内置) | ziparchive (内置) | sharpziplib (第三方) |
---|---|---|---|
易用性 | 高 | 中 | 中 |
功能丰富度 | 基础 | 中等 | 高(加密、unicode支持等) |
性能 | 良好 | 良好 | 良好 |
无需额外依赖 | 是 | 是 | 否 |
跨平台兼容性 | 是 | 是 | 是 |
推荐场景 | 简单压缩/解压 | 需精细控制 | 复杂需求(如加密) |
总结
在c#中实现zip压缩和解压,我们可根据需求选择:
- 简单场景:使用内置的
zipfile
类(zipfile.createfromdirectory
和zipfile.extracttodirectory
)最方便。 - 需精细控制或多文件/文件夹混合:使用
ziparchive
类逐项添加内容更灵活。 - 有高级需求(如加密、更高压缩比):
sharpziplib
等第三方库功能更强大。
处理多文件和文件夹时,递归添加是保持目录结构的关键。无论用哪种方法,都请注意添加适当的错误处理(如 try-catch 块)以确保程序健壮性。
到此这篇关于c#压缩解压文件的常用方法的文章就介绍到这了,更多相关c#压缩解压文件内容请搜索代码网以前的文章或继续浏览下面的相关文章希望大家以后多多支持代码网!
发表评论