Craft Your Own Archiver 1 / 3






3.29/5 (6 votes)
This article describes how to perform list, extract, add and operations to archives using CAKE3.
Introduction
Many years ago, when I start learning how to develop software, zippware is one of my first products I developed, I developed my first prototype using a demo of DelZip.
I found that developing such a product is a good way to learn how to program window programs. To build the most basic zippware, you have to learn how to do many things using the existing framework, like User Interface, IO handling, Shell, Win32 API. Once you completed the basics, you can apply most new features that you just learned, like backup support, CD burner support.
There are many ways to develop an zippware, but if you want to develop one that supports a very wide range of archive types, you will either have to purchase an expensive commercial solutions, or write a lot of code to support each archive types. I chose to write my own code, and I released them since 2001 (named CAKE), the source code is under LGPL license, you are free to use it to develop your own archiver.
Because CAKE3 lacks documentation, I write this tutorial to explain how to write the most basic archiver using CAKE3.
This tutorial includes 3 parts:
- Archive Operations (this article)
- File List, Directory Tree and Drag n Drop
- Threading support
CAKE (Common Archiver Kit Experiment) History
Back in around 2001, when first developed, there were many freeware archive support components, each support a few archive formats, so CAKE is written to combine these components to support wider range of archives. Because it was developed under Delphi, users of the component have to install around 9 components before installing CAKE.
(e.g. CAKE2
<-----> Cmarc
<-----> 7zip-32.dll)
In 2006, CAKE is being ported to dotNet environment (CAKE3.NET), the code of archive handling is rewritten, no longer requires the middle layer, and all external w32 DLL is called directly. To make the port easier, some Delphi commands (AppendSlash
, ExtractFileName
) are ported as well, all under Cake3.Utils
class. Add files to archive using relative path is also possible in this version.
(e.g. CAKE3
<-----> 7-zip32.dll)
Structure of Cake
Cake3
(Cake3.dll)Cakdir3
: Main class, most archive operation does hereContentList
: A list containing Content Type (you can read it asList<ContentType>
)ContentType
: Represent a file in an archiveDefines
: Definition of misc structures- Add / Delete / Extract / SFXOptions
- Queue: For support threading, will be explained in future articles
CakdirThreadQueue
CakdirWorkItem
ThreadQueueMonitor
Utils
: All tools available- {CakArchiver, connect other dotNet components or DLL}
Ace
Cmarc
IconLib
InstallBuild
Rar
SharpZipLib
Sqx
WcxPlugins
Craft Your Own Archiver 1
Please note that in the attached demo, all archive handling routines are placed in separate methods (from UI), this will make the program easier to modify.
This demo requires VS2008, if you want to use SharpDevelop, please recreate the project then add the source again.
To Open an Archive
1) Cakdir3 cakdir = new Cakdir3(archiveName);
- Quite simple, just noted that you have to create a new instance of
Cakdir3
everytime you open a new archive.If the archive does not exist, it will create it when you add file(s) to archive (see below).
To List Archive Contents (to a listview named lvFileList)
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) }
- Line 2 requests
cakdir3
to perform list content, you can specify other mask as well (keep in mind only * is supported, ? is not supported). - Line 3,
cakdir.Archive_Contents
is aContentList
containing zero or moreContentTypes
. - Line 5 creates a new
ListViewItem
for each entry,Utils.SizeInK
converts anint
tokb string
, (e.g.74550000
---> "745.50 kb
")
The listing is working now, however it looks unattractive without icons, so we shall add Icon support now.
To List Archive Contents with Icons
You have to create an ImageList
named (imageS
, means small images) in MainForm
, hook it to 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);
- Line5.1 specifies an
imagekey
, which is based on the extension of file (Utils.ExtractFileExt extract ext
from astring
) - Line5.2 and 5.3, if image list does not contain the
imagekey
, it will retrieve an icon for the specified extension and add it to image list.(
Utils.GetSmallFileIcon()
uses W32 API (SHGetFileInfo
) to retrieve icon. You can findUtils.GetLargeFileIcon
as well).
To Extract Files from Archive
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();
- Line 2, you can use
CanExtract
to see if files can be extracted from specified archive, there's alsoCanList
/CanAdd
if you want to check if archive without opening it, use (
Cakdir3.GetArchiveType(".zip").CanExtract
) instead. - Line 3-6, all extract related options are located in
ExtractOptions
archiveName
: name of archive, you don't have to touch this normally.allowFolder
: whether use folder informationdialogless
: some archiver DLL does show progress dialog when executing, enable this will disable the DLLsextractFolder
: specify where to extract.extractItem
: specify item to extractextractOverwrite
: whether to overwrite existing filespassword
: specify passwordResetExtractItem()
: setextractItem
to "*"
- Line 7 will return
true
if extract is success,alternatively you can call the following method instead.
3) cakdir.Extract(filter, extractTo, useFolder, allowOverwrite);
The following method can extract file recursively (e.g. "outer.zip\inner.zip\core.zip")
3) Utils.ExtractArchiveRecrusive(archiveName, extrOptions);
To Add Files to Archive
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("*");
- Line 3-4, all add related options is located in
AddOptions
addCompressLevel
: 0..9, cake does not have individual compression method support yetaddFile
: file to addaddFolder
: how to store folder information, select one offolderMode
below:folderMode Description if add "c:\ temp \ test \ file.txt" and set baseFolder as "c:\temp"
full Store full folder information. \ temp \ test \ file.txt none Store no folder information. file.txt relative Store folder information relative to baseFolder
.\ test \ file.txt addMode
: how to add file, select one of theupdateMode
below:updateMode Description add
Add all specified files to the archive refresh
Update older files in the archive and add files that are new to the archive update
Update specified files in the archive that are older than the selected disk files synchronize
Replace if newer, add even if not present in archive, delete if not present in disk archiveName
: name of archive, you don't have to touch this normallybaseFolder
: base folder ifaddFolder = relative
dialogless
: some archiver DLL does show progress dialog when executing, enable this will disable the DLLspassword
: specify passworddefaultOptions()
: revert back to default options
- Line 5 will return
true
if add is success,Please note that all operations (Add / Extract / Delete) are not threaded.
- Line 6 forces
cakdir3
to perform list content again.
To Delete Files from Archive
1) if (cakdir == null) return;
2) if (!cakdir.CanAdd) return;
3) cakdir.DeleteOptions.deleteFile = deleteFile;
4) cakdir.Delete();
5) cakdir.List("*");
- Line 3, all delete related options is located in
DeleteOptions
archiveName
: Name of archive, you don't have to touch this normallydeleteFile
: File to delete
- Line 4 will return
true
if add is success - Line 5 forces
cakdir3
to perform list content again
Handling Progress Message
Let user know what's working on.
1) cakdir.OnMessage += new MessageEventHandler(ProgressScreen_Message);
.....
2) void ProgressScreen_Message(object sender, MessageEventArgs e)
3) { tbMessage.Text += e.Message + Environment.NewLine; }
- Line 3 will append the message to a
textbox
(tbMessage
)
You can show display progress using a progress bar too:
1) cakdir.OnProgress += new MessageEventHandler(ProgressScreen_Progress);
.....
2) void ProgressScreen_Progress(object sender, MessageEventArgs e)
3) { pBar.Value = e.Percent; }
- Line 3 will set the percentage of progress bar (
pBar
), other properties inMessageEventArgs
:Percent
: Percentage completed (1..100)Filename
: File processing
Please note that progress bar is not completely working for all archivers yet.
Other events included in Cakdir3
:
OnStartWorking
/OnStopWorking
: Signal when start and finishOnError
: Signal when error occurredOnOverwrite
- When extract withextractOverwrite
set tofalse
, it signals when a file already exists. (if not overridden, internal overwrite handler is used)OnPassword
- signal when password requiredOnItemList
- usually for internal use, whenCakdir.InternalList
is on, list via this event instead ofArchive_Contents
When you completed this part, you should know how to use Cake3
to do most archive operations. The next article will describe how to improve the User Interface, implement virtual file list, directory tree and drag and drop support.
References
- Fesersoft's CRC32 implementation
- Using IFilter in C#
- Implementing the .NET IComparer interface to get a more natural sort order
- SharpZipLib
- IconLib
- Common Archiver Library (Cmarc)
History
- 12-05-2008 - First submitted to CodeProject