打造你自己的压缩工具 1 / 3






3.29/5 (6投票s)
本文介绍如何使用 CAKE3 执行列表、提取、添加和操作压缩文件。
引言
很多年前,当我开始学习如何开发软件时,zip软件是我开发的最早的产品之一,我使用 DelZip 的演示版开发了我的第一个原型。
我发现开发这样一个产品是学习如何编程窗口程序的绝佳方式。要构建最基本的 zip 软件,您必须学会如何使用现有框架做很多事情,例如用户界面、IO 处理、Shell、Win32 API。一旦完成了基础知识,您就可以应用您刚学到的所有新功能,例如备份支持、CD 刻录机支持。
开发 zip 软件有很多方法,但如果您想开发一个支持多种压缩文件类型的软件,您要么必须购买昂贵的商业解决方案,要么编写大量代码来支持每种压缩文件类型。我选择自己编写代码,并且自 2001 年以来就发布了它们(名为 CAKE),源代码是在 LGPL 许可下发布的,您可以自由使用它来开发自己的压缩工具。
由于 CAKE3 缺乏文档,我写了这个教程来解释如何使用 CAKE3 编写最基本的压缩工具。
本教程包含 3 部分
- 压缩操作(本文)
- 文件列表、目录树和拖放
- 多线程支持
CAKE (Common Archiver Kit Experiment) 历史
早在 2001 年首次开发时,市面上有许多免费的压缩文件支持组件,每个组件都支持几种压缩格式,因此 CAKE 的编写是为了整合这些组件以支持更广泛的压缩文件类型。由于它是用 Delphi 开发的,组件的用户在安装 CAKE 之前必须安装大约 9 个组件。
(例如:CAKE2
<-----> Cmarc
<-----> 7zip-32.dll)
2006 年,CAKE 被移植到 dotNet 环境(CAKE3.NET),压缩文件处理的代码被重写,不再需要中间层,并且所有外部 w32 DLL 都被直接调用。为了便于移植,一些 Delphi 命令(AppendSlash
、ExtractFileName
)也被移植过来,全部包含在 Cake3.Utils
类中。在此版本中,还可以使用相对路径向压缩文件中添加文件。
(例如:CAKE3
<-----> 7-zip32.dll)
Cake 结构
Cake3
(Cake3.dll)Cakdir3
:主类,大多数压缩操作在此进行ContentList
:一个包含内容类型的列表(您可以将其读取为List<ContentType>
)ContentType
:表示压缩文件中的一个文件Defines
:杂项结构的定义- 添加/删除/提取/SFX选项
- Queue:用于支持多线程,将在后续文章中解释
CakdirThreadQueue
CakdirWorkItem
ThreadQueueMonitor
Utils
:所有可用工具- {CakArchiver,连接其他 dotNet 组件或 DLL}
Ace
Cmarc
IconLib
InstallBuild
Rar
SharpZipLib
Sqx
WcxPlugins
打造你自己的压缩工具 1
请注意,在附带的演示程序中,所有压缩文件处理例程都放在与 UI 分开的方法中,这样可以使程序更容易修改。
此演示需要 VS2008,如果您想使用 SharpDevelop,请重新创建项目然后添加源代码。
打开一个压缩文件
1) Cakdir3 cakdir = new Cakdir3(archiveName);
- 很简单,只需注意,每次打开新压缩文件时都必须创建一个新的
Cakdir3
实例。如果压缩文件不存在,当您向其中添加文件时(见下文)它会创建它。
列出压缩文件内容(到名为 lvFileList 的 listview)
1) if (cakdir == null) return;
2) cakdir.List("*");
3) foreach (ContentType ct in cakdir.Archive_Contents)
4) {
5) ListViewItem item = new ListViewItem(new string[]
{ct.fileName, Utils.SizeInK(ct.fileSize) });
6) lvFileList.Items.Add(item);
7) }
- 第 2 行请求
cakdir3
执行列出内容的操作,您也可以指定其他掩码(请记住只支持 *,不支持 ?)。 - 第 3 行,
cakdir.Archive_Contents
是一个ContentList
,包含零个或多个ContentTypes
。 - 第 5 行,为每个条目创建一个新的
ListViewItem
,Utils.SizeInK
将一个int
转换为kb 字符串
(例如,74550000
---> "745.50 kb
")
列表现在可以工作了,但是没有图标看起来不吸引人,所以我们现在添加图标支持。
列出带图标的压缩文件内容
您必须在 MainForm
中创建一个名为(imageS
,表示小图标)的 ImageList
,并将其链接到 lvFileList.SmallIcons
。
5) ListViewItem item = new ListViewItem(new string[]
{ct.fileName, Utils.SizeInK(ct.fileSize) });
5.1) item.ImageKey = Utils.ExtractFileExt(ct.fileName).ToLower();
5.2) if (!imageS.Images.ContainsKey(item.ImageKey))
5.3) imageS.Images.Add(item.ImageKey, Utils.GetSmallFileIcon(ct.fileName));
6) lvFileList.Items.Add(item);
- 第 5.1 行指定了一个
imagekey
,它基于文件扩展名(Utils.ExtractFileExt extract ext
从一个string
中提取扩展名) - 第 5.2 行和 5.3 行,如果图像列表不包含
imagekey
,它将检索指定扩展名的图标并将其添加到图像列表中。(
Utils.GetSmallFileIcon()
使用 W32 API(SHGetFileInfo
)来检索图标。您也可以找到Utils.GetLargeFileIcon
。)
提取压缩文件中的文件
1) if (cakdir == null) return;
2) if (!cakdir.CanExtract) return;
3) cakdir.ExtractOptions.extractItem = new string[] { "*" };
4) cakdir.ExtractOptions.extractFolder = @"c:\temp";
5) cakdir.ExtractOptions.allowFolder = true;
6) cakdir.ExtractOptions.extractOverwrite = true;
7) bool success = cakdir.Extract();
- 第 2 行,您可以使用
CanExtract
来查看是否可以从指定的压缩文件中提取文件,还有一个CanList
/CanAdd
。如果您想在不打开压缩文件的情况下进行检查,可以使用(
Cakdir3.GetArchiveType(".zip").CanExtract
)。 - 第 3-6 行,所有与提取相关的选项都位于
ExtractOptions
中。archiveName
:压缩文件名,通常您不必修改它。allowFolder
:是否使用文件夹信息。dialogless
:一些压缩文件 DLL 在执行时会显示进度对话框,启用此项将禁用 DLL。extractFolder
:指定提取位置。extractItem
:指定要提取的项目。extractOverwrite
:是否覆盖现有文件。password
:指定密码。ResetExtractItem()
:将extractItem
设置为 "*"。
- 第 7 行将在提取成功时返回
true
。或者,您也可以调用以下方法。
3) cakdir.Extract(filter, extractTo, useFolder, allowOverwrite);
以下方法可以递归提取文件(例如,“outer.zip\inner.zip\core.zip”)
3) Utils.ExtractArchiveRecrusive(archiveName, extrOptions);
向压缩文件添加文件
1) if (cakdir == null) return;
2) if (!cakdir.CanAdd) return;
3) cakdir.AddOptions.addFile = addFile;
4) cakdir.AddOptions.addFolder = AddOptions.folderMode.full;
5) bool success = cakdir.Add();
6) cakdir.List("*");
- 第 3-4 行,所有与添加相关的选项都位于
AddOptions
中。addCompressLevel
:0..9,cake 尚不支持单独的压缩方法。addFile
:要添加的文件。addFolder
:如何存储文件夹信息,从下面的folderMode
中选择一个。folderMode 描述 如果添加 "c:\ temp \ test \ file.txt" 并将 baseFolder 设置为 "c:\temp"
full 存储完整的文件夹信息。 \ temp \ test \ file.txt none 存储不包含任何文件夹信息。 file.txt relative 存储相对于 baseFolder
的文件夹信息。\ test \ file.txt addMode
:如何添加文件,从下面的updateMode
中选择一个。updateMode 描述 加法
将所有指定的文件添加到压缩文件中。 刷新
更新压缩文件中较旧的文件,并添加新文件。 update
更新压缩文件中比选定磁盘文件旧的指定文件。 synchronize
如果较新则替换,即使未在压缩文件中找到也要添加,如果未在磁盘上找到则删除。 archiveName
:压缩文件名,通常您不必修改它。baseFolder
:当addFolder = relative
时的基准文件夹。dialogless
:一些压缩文件 DLL 在执行时会显示进度对话框,启用此项将禁用 DLL。password
:指定密码。defaultOptions()
:恢复到默认选项。
- 第 5 行将在添加成功时返回
true
。请注意,所有操作(添加/提取/删除)都不是多线程的。
- 第 6 行强制
cakdir3
再次执行列出内容的操作。
从压缩文件中删除文件
1) if (cakdir == null) return;
2) if (!cakdir.CanAdd) return;
3) cakdir.DeleteOptions.deleteFile = deleteFile;
4) cakdir.Delete();
5) cakdir.List("*");
- 第 3 行,所有与删除相关的选项都位于
DeleteOptions
中。archiveName
:压缩文件名,通常您不必修改它。deleteFile
:要删除的文件。
- 第 4 行将在添加成功时返回
true
。 - 第 5 行强制
cakdir3
再次执行列出内容的操作。
处理进度消息
让用户知道正在进行什么工作。
1) cakdir.OnMessage += new MessageEventHandler(ProgressScreen_Message);
.....
2) void ProgressScreen_Message(object sender, MessageEventArgs e)
3) { tbMessage.Text += e.Message + Environment.NewLine; }
- 第 3 行会将消息追加到
textbox
(tbMessage
)中。
您也可以使用进度条显示进度。
1) cakdir.OnProgress += new MessageEventHandler(ProgressScreen_Progress);
.....
2) void ProgressScreen_Progress(object sender, MessageEventArgs e)
3) { pBar.Value = e.Percent; }
- 第 3 行将设置进度条(
pBar
)的百分比,其他属性在MessageEventArgs
中。Percent
:完成百分比(1..100)。Filename
:正在处理的文件。
请注意,进度条并非对所有压缩文件都完全有效。
Cakdir3
中包含的其他事件
OnStartWorking
/OnStopWorking
:开始和完成时的信号。OnError
:发生错误时的信号。OnOverwrite
- 当提取时extractOverwrite
设置为false
,它会在文件已存在时发出信号(如果未覆盖,则使用内部覆盖处理程序)。OnPassword
- 需要密码时发出信号。OnItemList
- 通常供内部使用,当Cakdir.InternalList
开启时,通过此事件列出,而不是通过Archive_Contents
。
完成此部分后,您应该知道如何使用 Cake3
执行大多数压缩操作。下一篇文章将介绍如何改进用户界面,实现虚拟文件列表、目录树和拖放支持。
参考文献
- Fesersoft 的 CRC32 实现
- 在 C# 中使用 IFilter
- 实现 .NET IComparer 接口以获得更自然的排序顺序
- SharpZipLib
- IconLib
- 通用压缩库 (Cmarc)
历史
- 2008-05-12 - 首次提交至 CodeProject