Introduction
Ever wanted to know how to compress files without using a 3rd party library? Well as pointless as it may seem, I'm going to explain how.
Background
My drive to get this working was to allow me to use ExpressMaint utility and compress my databases. So here I am writing my first article on The Code Project.
Breaking Down a Zip File
Firstly this is hack, so we need to understand how a zip file is made, to demonstrate I've used a hex editor (binary editor) to show you.
I created an empty zip file in Windows by right clicking in a folder:
Great, now we see an empty zip file, of 22 bytes.
Then we add a text file which contains the text “Hello World”, just for comparison:
For those of you who'd like to get a better understanding of what the header of a *.zip comprises, this is the header break down:
- local file header signature 4 bytes (0x04034b50)
- version needed to extract 2 bytes
- general purpose bit flag 2 bytes
- compression method 2 bytes
- last mod file time 2 bytes
- last mod file date 2 bytes
- crc-32 4 bytes
- compressed size 4 bytes
- uncompressed size 4 bytes
- file name length 2 bytes
- extra field length 2 bytes
- file name (variable size)
- extra field (variable size)
Ok, so looking at this we obviously don't need to cater for the following fields in the header, as we only need 22 bytes for an empty file:
- uncompressed size 4 bytes
- file name length 2 bytes
- extra field length 2 bytes
Ok, enough theory, let’s have some fun...
The reason I suffixed this article with “Neat little Hack” is because we are going to use the Shell32.dll to copy a file or folder to the destination zip file, which Windows supports natively.
This leaves one flaw; we need a destination file... which we will create manually, hence getting to know the theory.
How to create the *.zip file in VB.NET and C#.
VB.NET
Public Sub CreateZipFile(ByVal Filename As String)
Dim Encoder As New System.Text.ASCIIEncoding
Dim Header As String = "PK" & Chr(5) & Chr(6)
Header = Header.PadRight(22, Chr(0))
My.Computer.FileSystem.WriteAllBytes(Filename, Encoder.GetBytes(Header), False)
End Sub
C#
public void CreateZipFile(string filename)
{
System.Text.ASCIIEncoding Encoder = new System.Text.ASCIIEncoding();
string sHeader = "PK" + (char)5 + (char)6;
sHeader = sHeader.PadRight(22, (char)0);
byte[] baHeader = System.Text.Encoding.ASCII.GetBytes(sHeader);
FileStream fs = File.Create(filename);
fs.Write(baHeader, 0, baHeader.Length);
fs.Flush();
fs.Close();
fs = null;
}
So what exactly have we accomplished? We have created an empty zip file which is the same as right clicking in a folder in Windows and choosing New > Compressed (Zipped) folder.
Now we have the function for creating the empty *.zip file, we are now ready to copy data to the file.
You need to add a reference to your shell32.dll file, which is found in your System32 folder.
As not all computer running Windows are setup the same, this is how you will find your Windows folder (including drive letter):
Now I can see my Windows folder is in the drive lettered C, and the folder is Windows. I now know that the file I'm looking for is in C:\Windows\System32.
In our Visual Studio project, we need to add a reference to this file, so right click on your Project in the Solution Explorer and select Add Reference:
Then select Browse, and locate the file:
How to copy a file or folder to a *.zip file in VB.NET and C#:
VB.NET
Public Sub ZipFile(ByVal Input As String, ByVal Filename As String)
Dim Shell As New Shell32.Shell
CreateZipFile(Filename)
Shell.NameSpace(Filename).CopyHere(Input)
Do Until Shell.NameSpace(Filename).Items.Count =
Shell.NameSpace(Input).Items.Count
System.Threading.Thread.Sleep(200)
System.Diagnostics.Debug.Print("Waiting...")
Loop
End Sub
C#
public void ZipFile(string Input, string Filename)
{
Shell32.Shell Shell = new Shell32.Shell();
CreateZipFile(Filename);
Shell.NameSpace(Filename).CopyHere(Input,0);
System.Threading.Thread.Sleep(2000);
}
}
Conclusion
Although it's not practical as one would need to code logic to handle existing zip files, it was fun writing this article and hopefully someone finds it interesting.