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 bytesReader: 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
- std.io.Writer — Detalhes da interface Writer
- std.io.Reader — Detalhes da interface Reader
- std.io Buffered — BufferedReader e BufferedWriter
- std.io.FixedBufferStream — Stream sobre buffer fixo
- getStdOut, getStdErr, getStdIn — Fluxos padrão
- std.fs.File — Tipo File que implementa Reader/Writer