std.io em Zig — Referência e Exemplos

std.io — Entrada e Saída

O módulo std.io é o ponto central para operações de entrada e saída no Zig. Ele fornece interfaces genéricas (Writer e Reader) que são implementadas por diversos tipos da biblioteca padrão, além de funções utilitárias para acessar os fluxos padrão do sistema operacional.

Visão Geral

O sistema de I/O do Zig é projetado com base em duas interfaces fundamentais:

  • Writer: interface genérica para escrita de bytes
  • Reader: interface genérica para leitura de bytes

Estas interfaces são implementadas como tipos genéricos parametrizados em tempo de compilação (comptime), o que permite ao compilador otimizar chamadas sem overhead de vtable em muitos casos.

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

Tipos Principais

io.AnyWriter

O tipo AnyWriter é uma versão type-erased do Writer, útil quando você precisa armazenar writers de tipos diferentes em uma mesma variável ou passá-los por interfaces não genéricas.

pub const AnyWriter = struct {
    context: *const anyopaque,
    writeFn: *const fn (*const anyopaque, []const u8) Error!usize,
};

io.AnyReader

Análogo ao AnyWriter, o AnyReader é a versão type-erased do Reader.

io.GenericWriter

O tipo parametrizado que define a interface Writer:

pub fn GenericWriter(
    comptime Context: type,
    comptime WriteError: type,
    comptime writeFn: fn (Context, []const u8) WriteError!usize,
) type

io.GenericReader

O tipo parametrizado que define a interface Reader:

pub fn GenericReader(
    comptime Context: type,
    comptime ReadError: type,
    comptime readFn: fn (Context, []u8) ReadError!usize,
) type

Funções Utilitárias

Acesso aos Fluxos Padrão

pub fn getStdOut() std.fs.File.Writer
pub fn getStdErr() std.fs.File.Writer
pub fn getStdIn() std.fs.File.Reader

Estas funções retornam writers/readers conectados aos descritores padrão do processo.

io.poll

pub fn poll(
    comptime StreamEnum: type,
    fifo_or_fd: anytype,
    buf: []u8,
) PollResult

Função de polling para múltiplos descritores de arquivo.

Exemplo 1: Escrita na Saída Padrão

O uso mais básico de std.io é escrever na saída padrão:

const std = @import("std");

pub fn main() !void {
    const stdout = std.io.getStdOut().writer();

    try stdout.print("Olá, {s}! Você tem {d} anos.\n", .{ "Maria", 25 });
    try stdout.writeAll("Esta é uma linha completa.\n");

    // Escrevendo bytes brutos
    const dados: [4]u8 = .{ 72, 101, 108, 111 };
    try stdout.writeAll(&dados); // Escreve "Helo"
    try stdout.writeByte('\n');
}

Exemplo 2: Leitura da Entrada Padrão

Lendo entrada do usuário linha por linha:

const std = @import("std");

pub fn main() !void {
    const stdin = std.io.getStdIn().reader();
    const stdout = std.io.getStdOut().writer();

    try stdout.writeAll("Digite seu nome: ");

    // Lê uma linha (até 1024 bytes), descartando o '\n'
    var buf: [1024]u8 = undefined;
    if (stdin.readUntilDelimiterOrEof(&buf, '\n')) |linha| {
        if (linha) |texto| {
            try stdout.print("Olá, {s}!\n", .{texto});
        }
    } else |err| {
        try stdout.print("Erro ao ler: {}\n", .{err});
    }
}

Exemplo 3: Writer Genérico com Função Customizada

Criando uma função que aceita qualquer tipo de Writer:

const std = @import("std");

fn gerarRelatorio(writer: anytype) !void {
    try writer.writeAll("=== Relatório ===\n");
    for (0..5) |i| {
        try writer.print("Item {d}: valor = {d}\n", .{ i, i * 42 });
    }
    try writer.writeAll("=================\n");
}

pub fn main() !void {
    // Escrevendo para stdout
    const stdout = std.io.getStdOut().writer();
    try gerarRelatorio(stdout);

    // Escrevendo para um buffer em memória
    var buf: [4096]u8 = undefined;
    var stream = std.io.fixedBufferStream(&buf);
    try gerarRelatorio(stream.writer());

    // O conteúdo escrito está disponível no buffer
    const conteudo = stream.getWritten();
    std.debug.print("Bytes escritos: {d}\n", .{conteudo.len});
}

Padrões Comuns

Função Genérica com anytype

O padrão mais idiomático em Zig para trabalhar com I/O é aceitar anytype como parâmetro de writer/reader:

fn processar(reader: anytype, writer: anytype) !void {
    while (try reader.readUntilDelimiterOrEof('\n')) |linha| {
        try writer.print(">> {s}\n", .{linha});
    }
}

Buffering

Para melhorar o desempenho de I/O, use BufferedWriter e BufferedReader:

const arquivo = try std.fs.cwd().openFile("dados.txt", .{});
defer arquivo.close();

var buf_reader = std.io.bufferedReader(arquivo.reader());
const reader = buf_reader.reader();

Tratamento de Erros

Todas as operações de I/O retornam error unions. Use try para propagar ou catch para tratar:

writer.writeAll("dados") catch |err| {
    std.log.err("Falha na escrita: {}", .{err});
    return err;
};

Módulos Relacionados

Tutoriais e Receitas Relacionados

Continue aprendendo Zig

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