Skip to content

Quick Start

This guide covers the essential compressionz APIs with practical examples.

The simplest usage requires just two functions:

const std = @import("std");
const cz = @import("compressionz");
pub fn main() !void {
var gpa = std.heap.GeneralPurposeAllocator(.{}){};
defer _ = gpa.deinit();
const allocator = gpa.allocator();
const original = "Hello, compressionz! This text will be compressed.";
// Compress
const compressed = try cz.compress(.zstd, original, allocator);
defer allocator.free(compressed);
// Decompress
const decompressed = try cz.decompress(.zstd, compressed, allocator);
defer allocator.free(decompressed);
std.debug.print("Original: {d} bytes\n", .{original.len});
std.debug.print("Compressed: {d} bytes\n", .{compressed.len});
std.debug.print("Match: {}\n", .{std.mem.eql(u8, original, decompressed)});
}

Change the codec by swapping the enum value:

// Fast, good ratio (recommended for most cases)
const zstd = try cz.compress(.zstd, data, allocator);
// Maximum speed
const lz4 = try cz.compress(.lz4, data, allocator);
// Self-describing, real-time
const snappy = try cz.compress(.snappy, data, allocator);
// Universal compatibility
const gzip = try cz.compress(.gzip, data, allocator);
// Best compression ratio
const brotli = try cz.compress(.brotli, data, allocator);

Control the speed/ratio trade-off:

// Fastest compression, lower ratio
const fast = try cz.compressWithOptions(.zstd, data, allocator, .{
.level = .fast,
});
// Best compression, slower
const best = try cz.compressWithOptions(.zstd, data, allocator, .{
.level = .best,
});
// Available levels: .fastest, .fast, .default, .better, .best

Protect against decompression bombs (malicious data that expands massively):

const decompressed = try cz.decompressWithOptions(.zstd, compressed, allocator, .{
.max_output_size = 100 * 1024 * 1024, // 100 MB limit
});

If the decompressed size exceeds the limit, returns error.OutputTooLarge.

Automatically detect the compression format from magic bytes:

fn decompressUnknown(data: []const u8, allocator: std.mem.Allocator) ![]u8 {
if (cz.Codec.detect(data)) |codec| {
return cz.decompress(codec, data, allocator);
}
return error.UnknownFormat;
}

Process large files without loading everything into memory:

const std = @import("std");
const cz = @import("compressionz");
pub fn compressFile(allocator: std.mem.Allocator, input_path: []const u8, output_path: []const u8) !void {
// Open files
const input = try std.fs.cwd().openFile(input_path, .{});
defer input.close();
const output = try std.fs.cwd().createFile(output_path, .{});
defer output.close();
// Create streaming compressor
var compressor = try cz.compressor(.gzip, allocator, output.writer(), .{});
defer compressor.deinit();
// Stream data through compressor
var buf: [4096]u8 = undefined;
while (true) {
const n = try input.read(&buf);
if (n == 0) break;
try compressor.writer().writeAll(buf[0..n]);
}
// Finalize
try compressor.finish();
}
pub fn decompressFile(allocator: std.mem.Allocator, input_path: []const u8) ![]u8 {
const file = try std.fs.cwd().openFile(input_path, .{});
defer file.close();
var decompressor = try cz.decompressor(.gzip, allocator, file.reader());
defer decompressor.deinit();
return decompressor.reader().readAllAlloc(allocator, 100 * 1024 * 1024);
}

Extract files from a ZIP archive:

const cz = @import("compressionz");
pub fn extractZip(allocator: std.mem.Allocator, zip_data: []const u8) !void {
const files = try cz.archive.extractZip(allocator, zip_data);
defer {
for (files) |f| {
allocator.free(f.name);
allocator.free(f.data);
}
allocator.free(files);
}
for (files) |file| {
std.debug.print("{s}: {d} bytes\n", .{ file.name, file.data.len });
}
}

Create a ZIP archive:

const files = [_]cz.archive.FileEntry{
.{ .name = "hello.txt", .data = "Hello, World!" },
.{ .name = "data.json", .data = "{\"key\": \"value\"}" },
};
const zip_data = try cz.archive.createZip(allocator, &files);
defer allocator.free(zip_data);

compressionz uses a unified error type:

const result = cz.decompress(.zstd, data, allocator) catch |err| switch (err) {
error.InvalidData => {
std.debug.print("Corrupted or invalid data\n", .{});
return err;
},
error.ChecksumMismatch => {
std.debug.print("Data integrity check failed\n", .{});
return err;
},
error.OutputTooLarge => {
std.debug.print("Decompressed size exceeds limit\n", .{});
return err;
},
error.OutOfMemory => {
std.debug.print("Allocation failed\n", .{});
return err;
},
else => return err,
};

Here’s a complete program that compresses a file with multiple codecs and reports results:

const std = @import("std");
const cz = @import("compressionz");
pub fn main() !void {
var gpa = std.heap.GeneralPurposeAllocator(.{}){};
defer _ = gpa.deinit();
const allocator = gpa.allocator();
// Read input file
const args = try std.process.argsAlloc(allocator);
defer std.process.argsFree(allocator, args);
if (args.len < 2) {
std.debug.print("Usage: {s} <file>\n", .{args[0]});
return;
}
const data = try std.fs.cwd().readFileAlloc(allocator, args[1], 100 * 1024 * 1024);
defer allocator.free(data);
std.debug.print("Original size: {d} bytes\n\n", .{data.len});
std.debug.print("{s:<12} {s:>12} {s:>10}\n", .{ "Codec", "Size", "Ratio" });
std.debug.print("{s}\n", .{"-" ** 36});
// Test each codec
inline for ([_]cz.Codec{ .lz4, .snappy, .zstd, .gzip, .brotli }) |codec| {
const compressed = try cz.compress(codec, data, allocator);
defer allocator.free(compressed);
const ratio = 100.0 * (1.0 - @as(f64, @floatFromInt(compressed.len)) /
@as(f64, @floatFromInt(data.len)));
std.debug.print("{s:<12} {d:>12} {d:>9.1}%\n", .{
codec.name(),
compressed.len,
ratio,
});
}
}

You now know the basics! Continue with: