std.compress em Zig — Referência e Exemplos

std.compress — Compressão e Descompressão

O módulo std.compress fornece implementações de algoritmos de compressão e descompressão de dados escritas em Zig puro. Ele suporta os formatos mais comuns da web e de sistemas — deflate, gzip, zlib e zstd — permitindo processar arquivos comprimidos, respostas HTTP comprimidas e dados serializados sem dependências externas de C.

Visão Geral

const std = @import("std");
const compress = std.compress;

Algoritmos Disponíveis

MóduloFormatoUso Comum
compress.flateDEFLATE (RFC 1951)Formato base para gzip/zlib
compress.gzipgzip (RFC 1952)Arquivos .gz, HTTP
compress.zlibzlib (RFC 1950)PNG, HTTP, protocolos
compress.zstdZstandardCompressão moderna de alto desempenho
compress.lzmaLZMA/XZArquivos .xz

Interface Comum

Todos os descompressores seguem o padrão de Reader do Zig:

// Descompressão: envolvem um Reader e retornam outro Reader
pub fn decompressor(reader: anytype) Decompressor

// Compressão: envolvem um Writer e retornam outro Writer
pub fn compressor(writer: anytype, options: Options) Compressor

Exemplo 1: Compressão e Descompressão com Gzip

const std = @import("std");

pub fn main() !void {
    var gpa = std.heap.GeneralPurposeAllocator(.{}){};
    defer _ = gpa.deinit();
    const allocator = gpa.allocator();

    const dados_originais = "Zig é uma linguagem de programação de sistemas " ++
        "focada em segurança, desempenho e legibilidade. " ++
        "Esta string será comprimida e depois descomprimida " ++
        "para demonstrar o módulo std.compress. " ++
        "A compressão é especialmente eficaz em textos repetitivos " ++
        "como este, onde padrões comuns podem ser aproveitados." ** 3;

    const stdout = std.io.getStdOut().writer();
    try stdout.print("Dados originais: {d} bytes\n", .{dados_originais.len});

    // Comprime com gzip
    var buf_comprimido = std.ArrayList(u8).init(allocator);
    defer buf_comprimido.deinit();

    var compressor = try std.compress.gzip.compressor(buf_comprimido.writer(), .{});
    try compressor.writer().writeAll(dados_originais);
    try compressor.finish();

    try stdout.print("Comprimido:      {d} bytes\n", .{buf_comprimido.items.len});

    const razao = @as(f64, @floatFromInt(buf_comprimido.items.len)) /
        @as(f64, @floatFromInt(dados_originais.len)) * 100.0;
    try stdout.print("Razão:           {d:.1}%\n", .{razao});

    // Descomprime
    var stream = std.io.fixedBufferStream(buf_comprimido.items);
    var decompressor = std.compress.gzip.decompressor(stream.reader());

    var buf_descomprimido = std.ArrayList(u8).init(allocator);
    defer buf_descomprimido.deinit();

    const decompressor_reader = decompressor.reader();
    var tmp: [4096]u8 = undefined;
    while (true) {
        const n = try decompressor_reader.read(&tmp);
        if (n == 0) break;
        try buf_descomprimido.appendSlice(tmp[0..n]);
    }

    try stdout.print("Descomprimido:   {d} bytes\n", .{buf_descomprimido.items.len});
    try stdout.print("Integridade:     {}\n", .{
        std.mem.eql(u8, dados_originais, buf_descomprimido.items),
    });
}

Exemplo 2: Descompressão de Dados Zlib

const std = @import("std");

pub fn main() !void {
    var gpa = std.heap.GeneralPurposeAllocator(.{}){};
    defer _ = gpa.deinit();
    const allocator = gpa.allocator();

    const stdout = std.io.getStdOut().writer();

    // Comprime dados com zlib
    const texto = "Dados de exemplo para compressão zlib no Zig!";

    var buf_comprimido = std.ArrayList(u8).init(allocator);
    defer buf_comprimido.deinit();

    var comp = try std.compress.zlib.compressor(buf_comprimido.writer(), .{});
    try comp.writer().writeAll(texto);
    try comp.finish();

    try stdout.print("Original: {d} bytes -> zlib: {d} bytes\n", .{
        texto.len,
        buf_comprimido.items.len,
    });

    // Descomprime
    var stream = std.io.fixedBufferStream(buf_comprimido.items);
    var decomp = std.compress.zlib.decompressor(stream.reader());

    var resultado: [256]u8 = undefined;
    const reader = decomp.reader();
    var total: usize = 0;
    while (true) {
        const n = try reader.read(resultado[total..]);
        if (n == 0) break;
        total += n;
    }

    try stdout.print("Descomprimido: {s}\n", .{resultado[0..total]});
    try stdout.print("Correto: {}\n", .{std.mem.eql(u8, texto, resultado[0..total])});
}

Exemplo 3: Compressão Deflate de Baixo Nível

const std = @import("std");

fn comprimirDados(dados: []const u8, allocator: std.mem.Allocator) ![]u8 {
    var buf = std.ArrayList(u8).init(allocator);
    errdefer buf.deinit();

    var comp = try std.compress.flate.compressor(buf.writer(), .{});
    try comp.writer().writeAll(dados);
    try comp.finish();

    return try buf.toOwnedSlice();
}

fn descomprimirDados(comprimido: []const u8, allocator: std.mem.Allocator) ![]u8 {
    var stream = std.io.fixedBufferStream(comprimido);
    var decomp = std.compress.flate.decompressor(stream.reader());

    var buf = std.ArrayList(u8).init(allocator);
    errdefer buf.deinit();

    var tmp: [4096]u8 = undefined;
    const reader = decomp.reader();
    while (true) {
        const n = try reader.read(&tmp);
        if (n == 0) break;
        try buf.appendSlice(tmp[0..n]);
    }

    return try buf.toOwnedSlice();
}

pub fn main() !void {
    var gpa = std.heap.GeneralPurposeAllocator(.{}){};
    defer _ = gpa.deinit();
    const allocator = gpa.allocator();

    const stdout = std.io.getStdOut().writer();

    // Testa com diferentes tipos de dados
    const testes = [_]struct { nome: []const u8, dados: []const u8 }{
        .{ .nome = "Texto repetitivo", .dados = "AAAAAAAAAA" ** 100 },
        .{ .nome = "Texto natural", .dados = "O Zig compila para código nativo eficiente." },
        .{ .nome = "Dados aleatórios", .dados = "jK8mN2pQ5rT" ** 10 },
    };

    try stdout.writeAll("=== Benchmark de Compressão (deflate) ===\n\n");
    try stdout.print("{s:<25} {s:>8} {s:>10} {s:>8}\n", .{
        "Tipo", "Original", "Comprimido", "Razão",
    });

    for (testes) |teste| {
        const comprimido = try comprimirDados(teste.dados, allocator);
        defer allocator.free(comprimido);

        // Verifica integridade
        const descomprimido = try descomprimirDados(comprimido, allocator);
        defer allocator.free(descomprimido);

        const razao = @as(f64, @floatFromInt(comprimido.len)) /
            @as(f64, @floatFromInt(teste.dados.len)) * 100.0;

        try stdout.print("{s:<25} {d:>7}B {d:>9}B {d:>6.1}%\n", .{
            teste.nome,
            teste.dados.len,
            comprimido.len,
            razao,
        });
    }
}

Módulos Relacionados

Tutoriais e Receitas Relacionados

Continue aprendendo Zig

Explore mais tutoriais e artigos em português para dominar a linguagem Zig.