Working with ZipFile and GZipStream in C
Handling data compression in .NET is primarily managed through the
System.IO.Compression namespace. This article provides a
practical guide on how to work with compressed archives in C# using both
ZipFile and GZipStream. You will learn when to
choose each approach, how to create and extract multi-file ZIP archives
using ZipFile, and how to compress and decompress single
files or memory streams using GZipStream.
Understanding ZipFile vs. GZipStream
While both classes compress data, they serve different purposes:
ZipFile(andZipArchive): Designed to work with standard.zipfiles containing multiple files and nested directories. It manages file metadata, paths, and directory structures.GZipStream: Designed to compress a single stream of raw bytes using the GZIP format (.gz). It does not store directory structures or multiple files natively unless paired with a container format like TAR.
Working with ZipFile
The static ZipFile class provides straightforward
methods for creating, extracting, and opening .zip archives
on disk.
1. Creating a ZIP Archive from a Directory
You can compress an entire directory into a .zip file
using ZipFile.CreateFromDirectory:
using System;
using System.IO.Compression;
class Program
{
static void Main()
{
string sourceDirectory = @"C:\data\reports";
string destinationZip = @"C:\data\reports.zip";
// Compresses the folder and includes the base directory structure
ZipFile.CreateFromDirectory(sourceDirectory, destinationZip, CompressionLevel.Optimal, includeBaseDirectory: false);
Console.WriteLine("ZIP archive created successfully.");
}
}2. Extracting a ZIP Archive to a Directory
To unpack a .zip archive to a target folder, use
ZipFile.ExtractToDirectory:
using System;
using System.IO.Compression;
class Program
{
static void Main()
{
string zipPath = @"C:\data\reports.zip";
string extractPath = @"C:\data\extracted_reports";
// Extracts all entries; overwriteFiles can be set to true if needed
ZipFile.ExtractToDirectory(zipPath, extractPath, overwriteFiles: true);
Console.WriteLine("ZIP archive extracted successfully.");
}
}3. Adding or Reading Individual Entries with ZipArchive
If you need finer control over archive contents without extracting
everything to disk, use ZipArchive:
using System;
using System.IO;
using System.IO.Compression;
class Program
{
static void Main()
{
string zipPath = @"C:\data\reports.zip";
// Open an existing archive to add a new file
using (FileStream zipToOpen = new FileStream(zipPath, FileMode.Open))
using (ZipArchive archive = new ZipArchive(zipToOpen, ZipArchiveMode.Update))
{
ZipArchiveEntry entry = archive.CreateEntry("notes.txt");
using (StreamWriter writer = new StreamWriter(entry.Open()))
{
writer.WriteLine("Archive created on: " + DateTime.UtcNow);
}
}
// Reading entries from an archive
using (ZipArchive archive = ZipFile.OpenRead(zipPath))
{
foreach (ZipArchiveEntry entry in archive.Entries)
{
Console.WriteLine($"File: {entry.FullName}, Compressed Size: {entry.CompressedLength} bytes");
}
}
}
}Working with GZipStream
GZipStream wraps an underlying stream to compress or
decompress data on the fly. It is commonly used for network transfers,
caching, or single-file compression.
1. Compressing a File with GZipStream
To compress a file into .gz format, read the source file
into a stream and pipe it through a GZipStream:
using System;
using System.IO;
using System.IO.Compression;
class Program
{
static void Main()
{
string sourceFile = @"C:\data\large_log.txt";
string compressedFile = @"C:\data\large_log.txt.gz";
using (FileStream sourceStream = File.OpenRead(sourceFile))
using (FileStream targetStream = File.Create(compressedFile))
using (GZipStream compressionStream = new GZipStream(targetStream, CompressionLevel.Optimal))
{
sourceStream.CopyTo(compressionStream);
}
Console.WriteLine("File compressed with GZip.");
}
}2. Decompressing a File with GZipStream
To decompress a .gz file back to its original state,
wrap the compressed file stream in a GZipStream set to
CompressionMode.Decompress:
using System;
using System.IO;
using System.IO.Compression;
class Program
{
static void Main()
{
string compressedFile = @"C:\data\large_log.txt.gz";
string decompressedFile = @"C:\data\restored_log.txt";
using (FileStream sourceStream = File.OpenRead(compressedFile))
using (FileStream targetStream = File.Create(decompressedFile))
using (GZipStream decompressionStream = new GZipStream(sourceStream, CompressionMode.Decompress))
{
decompressionStream.CopyTo(targetStream);
}
Console.WriteLine("File decompressed successfully.");
}
}3. Compressing In-Memory Byte Arrays
You can also use GZipStream with
MemoryStream to compress payloads in memory before storing
them in a database or sending them across a network:
using System;
using System.IO;
using System.IO.Compression;
using System.Text;
class Program
{
static byte[] CompressBytes(byte[] rawData)
{
using (MemoryStream memoryStream = new MemoryStream())
{
using (GZipStream gzip = new GZipStream(memoryStream, CompressionLevel.Fastest))
{
gzip.Write(rawData, 0, rawData.Length);
}
return memoryStream.ToArray();
}
}
static byte[] DecompressBytes(byte[] compressedData)
{
using (MemoryStream sourceStream = new MemoryStream(compressedData))
using (MemoryStream outputStream = new MemoryStream())
using (GZipStream gzip = new GZipStream(sourceStream, CompressionMode.Decompress))
{
gzip.CopyTo(outputStream);
return outputStream.ToArray();
}
}
static void Main()
{
string text = "Repeated text data designed for compression demonstration.";
byte[] raw = Encoding.UTF8.GetBytes(text);
byte[] compressed = CompressBytes(raw);
byte[] decompressed = DecompressBytes(compressed);
Console.WriteLine($"Original: {raw.Length} bytes");
Console.WriteLine($"Compressed: {compressed.Length} bytes");
Console.WriteLine($"Restored String: {Encoding.UTF8.GetString(decompressed)}");
}
}Summary of Best Practices
- Always Dispose Streams: Ensure that
GZipStreamandZipArchiveinstances are wrapped inusingstatements. Compression buffers are often flushed only upon disposal. - Select the Right CompressionLevel:
CompressionLevel.Optimal: Maximum compression, higher CPU usage.CompressionLevel.Fastest: Faster compression, slightly larger output.CompressionLevel.NoCompression: Useful only when wrapping files into a container format without size reduction.
- Path Traversal Protection: When extracting entries
via
ZipArchiveEntry, validate thatentry.FullNamedoes not resolve outside the target directory to prevent zip-slip vulnerabilities.