Zip files are the most ubiquitous compression format in computing history, with it first being invented in 1986 by Phillip Katz. Since then, the Zip file has found its way into every operating system as the de facto compression method. It’s only right that .NET developers become familiar with the format and have the necessary tools to work with these files programmatically.
In this post, we’ll look at the ZipFile
utility class, how to compress files and directories, along with decompressing zip files.
Using ZipFile System.IO.Compression
Microsoft introduced the ZipFile
class in .NET Framework 4.5, and developers can use the utility class on .NET 5, .NET Core 1.0+, UWP, and Xamarin.Forms targets. The ZipFile
static class is dependent on access to the file system; as such, any application looking to use this class also needs to reference the System.IO.Compression.FileSystem
assembly.
Create A Zip File Examples
The ZipFile
class has a CreateFromDirectory
method that takes a target directory and a destination path for the resulting zip file.
using System;
using System.IO;
using System.IO.Compression;
// using a target directory
// ZipFile will create
// the zip file on disk
ZipFile.CreateFromDirectory(
@"./",
@"./archive.zip"
);
Using the CreateFromDirectory
method, we can set several variables, including the compression level to Fastest
, Optimal
, and NoCompression
. The default compression seems to be Optimal
from looking through the code and is internally set on the ZipEntry
class when we provide no value.
using System;
using System.IO;
using System.IO.Compression;
ZipFile.CreateFromDirectory(
@"./",
"archive.zip",
compressionLevel: CompressionLevel.Fastest,
includeBaseDirectory: false,
entryNameEncoding: Encoding.UTF8);
For developers who want more control compressing a directory, they can loop through a directory’s contents and add files individually. The following technique is useful when we only want to add particular files, i.e., images or video files. It’s important to call Dispose
on the ZipArchive
to ensure the creation of a valid zip file. In the example below, we are declaring a scoped variable with the using
keyword.
using System;
using System.IO;
using System.IO.Compression;
var images = Directory.GetFiles(@"./", "*.png");
if (File.Exists("archive.zip"))
File.Delete("archive.zip");
using var archive =
ZipFile
.Open(@"archive.zip", ZipArchiveMode.Create);
foreach (var image in images)
{
var entry =
archive.CreateEntryFromFile(
image,
Path.GetFileName(image),
CompressionLevel.Optimal
);
Console.WriteLine($"{entry.FullName} was compressed.");
}
If we need to archive an entity that only exists in memory, we can use Stream
objects. We can use the CopyToAsync
method found on most streams to copy directly into our ZipEntry
instance.
using System;
using System.IO;
using System.IO.Compression;
var images = Directory.GetFiles(@"./", "*.png");
if (File.Exists("archive.zip"))
File.Delete("archive.zip");
using var archive =
ZipFile
.Open(@"archive.zip", ZipArchiveMode.Create);
// we're getting a file stream
// here but it could be any stream
var file = File.OpenRead(images[0]);
var entry =
archive.CreateEntry(
"test.png",
CompressionLevel.Optimal
);
await file.CopyToAsync(entry.Open());
Console.WriteLine($"{entry.FullName} was compressed.");
These are a few ways to create zip files in a C# application, but what about retrieving entries from a zip file?
Decompressing a Zip File Examples
The most straightforward approach is to use the ExtractToDirectory
method found on the ZipFile
class. This method will write entries to a directory on disk, which can then we can then access using our file system.
using System;
using System.IO;
using System.IO.Compression;
ZipFile.ExtractToDirectory(
@"./archive.zip",
@"./destination_directory",
overwriteFiles: true
);
If we need to perform post-processing for zip file entries, we can use the OpenFile
method on ZipFile
to create a ZipArchive
instance.
using System;
using System.IO;
using System.IO.Compression;
var archive = ZipFile.OpenRead(@"./archive.zip");
foreach (var entry in archive.Entries)
{
Console.WriteLine(entry.Name);
var stream = entry.Open();
// read stream
// push to the cloud?
// do whatever you like!
}
As we can see, the process of working with an existing zip file and its contents is straightforward, and the ability to work with Stream
instances gives us the ability to push resources from zip files to any other storage mechanism.
Conclusion
Zip files are an essential file format for a developer to understand. While not the most efficient compression format, it is ubiquitous and understood by all technology stacks. It allows us to pass logically grouped files in a single stream of data, which can be useful in many user scenarios. Luckily for .NET developers, the ZipFile
utility class provides more than enough functionality to deal with this compression approach, along with a multitude of ways we can work with this file format.
If you found this post helpful, please share it with your friends and co-workers. As always, thanks for reading.