SharpZipLib or formerly NZipLib is a Zip, GZip, Tar and BZip2 library written entirely in C# for the .NET platform. It is implemented as an assembly (installable in the GAC), and thus can easily be incorporated into other projects (in any .NET language). The creator of ziplib put it this way:
I've ported the zip library over to C# because I needed gzip/zip compression and I didn't want to use libzip.dll or something like this. I want all in pure C#.
Surely there are default tools to do it in .NET (at least for ZIP files) like System.IO.Compression
, however it doesn't offer all the features that a mature library like SharpZipLib does like the usage of password to protect the files etc. In this article we'll share with you, how to install the library in Visual Studio and how to accomplish tipical tasks with ZIP files as creating them or extracting them.
1. Install SharpZipLib via NuGet
The first you need to do is to install the library in your project via nuGet. Open your Winforms C# project and open the NuGet package manager in the solution explorer:
Go to the Browse tab and search for SharpZipLib
:
From the list select the package by ICSharpCode and install it. Once the installation of the package finishes, you will be able to use it in your classes. ziplib has intially been developed by Mike Krueger, however, much existing Java code helped a lot in speeding the creation of this library. Therefore credits fly out to other people.The current maintainer of ziplib is David Pierson. Please contact him regarding features, bugs etc via the forum or the official repository at Github here.
2. Using the Library
Note
In this article we will work only with ZIP files, however remember that the library works with different compression formats as TAR, GZip etc.
Basically after the installation you will need to import the namespaces that you require to create ZIP files namely:
using System.IO;
using ICSharpCode.SharpZipLib.Zip;
Examples
As usual on Our Code World, a code snippet means more than a thousand words, so we'll show in examples how you can achieve most of the tipical tasks when working with ZIP files with C#.
Create .zip from all files inside a folder
The following method compressDirectory
shows how to compress all the files inside a directory (string path) and attach them into a single zip file. The method expects as first argument the directory where the files are located, as second argument the path to the .zip file that will be generated and as last (optional) the compression level (0-9):
using System.IO;
using ICSharpCode.SharpZipLib.Zip;
/// <summary>
/// Method that compress all the files inside a folder (non-recursive) into a zip file.
/// </summary>
/// <param name="DirectoryPath"></param>
/// <param name="OutputFilePath"></param>
/// <param name="CompressionLevel"></param>
private void compressDirectory(string DirectoryPath, string OutputFilePath, int CompressionLevel = 9)
{
try
{
// Depending on the directory this could be very large and would require more attention
// in a commercial package.
string[] filenames = Directory.GetFiles(DirectoryPath);
// 'using' statements guarantee the stream is closed properly which is a big source
// of problems otherwise. Its exception safe as well which is great.
using (ZipOutputStream OutputStream = new ZipOutputStream(File.Create(OutputFilePath)))
{
// Define the compression level
// 0 - store only to 9 - means best compression
OutputStream.SetLevel(CompressionLevel);
byte[] buffer = new byte[4096];
foreach (string file in filenames)
{
// Using GetFileName makes the result compatible with XP
// as the resulting path is not absolute.
ZipEntry entry = new ZipEntry(Path.GetFileName(file));
// Setup the entry data as required.
// Crc and size are handled by the library for seakable streams
// so no need to do them here.
// Could also use the last write time or similar for the file.
entry.DateTime = DateTime.Now;
OutputStream.PutNextEntry(entry);
using (FileStream fs = File.OpenRead(file))
{
// Using a fixed size buffer here makes no noticeable difference for output
// but keeps a lid on memory usage.
int sourceBytes;
do
{
sourceBytes = fs.Read(buffer, 0, buffer.Length);
OutputStream.Write(buffer, 0, sourceBytes);
} while (sourceBytes > 0);
}
}
// Finish/Close arent needed strictly as the using statement does this automatically
// Finish is important to ensure trailing information for a Zip file is appended. Without this
// the created file would be invalid.
OutputStream.Finish();
// Close is important to wrap things up and unlock the file.
OutputStream.Close();
Console.WriteLine("Files successfully compressed");
}
}
catch (Exception ex)
{
// No need to rethrow the exception as for our purposes its handled.
Console.WriteLine("Exception during processing {0}", ex);
}
}
It can be used like:
compressDirectory(
@"C:\Users\user\Desktop\SomeFolder",
@"C:\Users\user\Desktop\SomeFolder\MyOutputFile.zip",
9
);
Create .zip with Password from all files inside a folder
If you want to define a password for the generated file, you only need to set the Password
property of the ZipOutputStream
instance with the password in string format:
/// <summary>
/// Method that compress all the files inside a folder (non-recursive) into a zip file.
/// </summary>
/// <param name="DirectoryPath"></param>
/// <param name="OutputFilePath"></param>
/// <param name="CompressionLevel"></param>
private void compressDirectoryWithPassword(string DirectoryPath, string OutputFilePath, string Password = null, int CompressionLevel = 9)
{
try
{
// Depending on the directory this could be very large and would require more attention
// in a commercial package.
string[] filenames = Directory.GetFiles(DirectoryPath);
// 'using' statements guarantee the stream is closed properly which is a big source
// of problems otherwise. Its exception safe as well which is great.
using (ZipOutputStream OutputStream = new ZipOutputStream(File.Create(OutputFilePath)))
{
// Define a password for the file (if providen)
// set its value to null or don't declare it to leave the file
// without password protection
OutputStream.Password = Password;
// Define the compression level
// 0 - store only to 9 - means best compression
OutputStream.SetLevel(CompressionLevel);
byte[] buffer = new byte[4096];
foreach (string file in filenames)
{
// Using GetFileName makes the result compatible with XP
// as the resulting path is not absolute.
ZipEntry entry = new ZipEntry(Path.GetFileName(file));
// Setup the entry data as required.
// Crc and size are handled by the library for seakable streams
// so no need to do them here.
// Could also use the last write time or similar for the file.
entry.DateTime = DateTime.Now;
OutputStream.PutNextEntry(entry);
using (FileStream fs = File.OpenRead(file))
{
// Using a fixed size buffer here makes no noticeable difference for output
// but keeps a lid on memory usage.
int sourceBytes;
do
{
sourceBytes = fs.Read(buffer, 0, buffer.Length);
OutputStream.Write(buffer, 0, sourceBytes);
} while (sourceBytes > 0);
}
}
// Finish/Close arent needed strictly as the using statement does this automatically
// Finish is important to ensure trailing information for a Zip file is appended. Without this
// the created file would be invalid.
OutputStream.Finish();
// Close is important to wrap things up and unlock the file.
OutputStream.Close();
Console.WriteLine("Files successfully compressed");
}
}
catch (Exception ex)
{
// No need to rethrow the exception as for our purposes its handled.
Console.WriteLine("Exception during processing {0}", ex);
}
}
This method can be used like:
// Or to use without password:
// string PasswordForZipFile = null;
string PasswordForZipFile = "ourcodeworld123";
compressDirectoryWithPassword(
@"C:\Users\user\Desktop\Folders",
@"C:\Users\user\Desktop\Folders\DestinationFile.zip",
PasswordForZipFile,
9
);
In this case, the password "ourcodeworld123" will protect the access to the content of the zip file.
Extract .zip content to a folder
The following method extracts the content of a zip file inside the specific folder. The first argument specifies the path to the file that you want to decompress, the second argument is the password of the file (you can set it to null if the file isn't password protected) and as last argument the path to the folder where the content of the file should be extracted:
/// <summary>
/// Extracts the content from a .zip file inside an specific folder.
/// </summary>
/// <param name="FileZipPath"></param>
/// <param name="password"></param>
/// <param name="OutputFolder"></param>
public void ExtractZipContent(string FileZipPath, string password, string OutputFolder)
{
ZipFile file = null;
try
{
FileStream fs = File.OpenRead(FileZipPath);
file = new ZipFile(fs);
if (!String.IsNullOrEmpty(password))
{
// AES encrypted entries are handled automatically
file.Password = password;
}
foreach (ZipEntry zipEntry in file)
{
if (!zipEntry.IsFile)
{
// Ignore directories
continue;
}
String entryFileName = zipEntry.Name;
// to remove the folder from the entry:- entryFileName = Path.GetFileName(entryFileName);
// Optionally match entrynames against a selection list here to skip as desired.
// The unpacked length is available in the zipEntry.Size property.
// 4K is optimum
byte[] buffer = new byte[4096];
Stream zipStream = file.GetInputStream(zipEntry);
// Manipulate the output filename here as desired.
String fullZipToPath = Path.Combine(OutputFolder, entryFileName);
string directoryName = Path.GetDirectoryName(fullZipToPath);
if (directoryName.Length > 0)
{
Directory.CreateDirectory(directoryName);
}
// Unzip file in buffered chunks. This is just as fast as unpacking to a buffer the full size
// of the file, but does not waste memory.
// The "using" will close the stream even if an exception occurs.
using (FileStream streamWriter = File.Create(fullZipToPath))
{
StreamUtils.Copy(zipStream, streamWriter, buffer);
}
}
}
finally
{
if (file != null)
{
file.IsStreamOwner = true; // Makes close also shut the underlying stream
file.Close(); // Ensure we release resources
}
}
}
It can be used like:
// If the file doesn't have password
ExtractZipContent(
@"C:\Users\user\Desktop\SomeFolder\TheFileToDecompress.zip",
null,
@"C:\Users\user\Desktop\outputfolder"
);
// If the file has password
ExtractZipContent(
@"C:\Users\user\Desktop\SomeFolder\TheFileToDecompress.zip",
"password123",
@"C:\Users\user\Desktop\outputfolder"
);
If you have another useful snippet with SharpZipLib that you may want to share with the community, or you need something related to the usage of this library, don't be shy and share your toughts in the comment box.
Happy coding !