Reader Interface em Zig — O que é e Como Usar
Definição
A Reader interface em Zig é o padrão utilizado pela biblioteca padrão para abstração de leitura de dados. Complementar à Writer interface, qualquer tipo que forneça uma função read com a assinatura correta pode ser usado como Reader. Isso permite escrever código genérico que lê de stdin, arquivos, buffers em memória, sockets de rede ou qualquer outra fonte de dados.
Por que Reader Interface Importa
- Código genérico: Funções que aceitam reader funcionam com qualquer fonte de dados.
- Testabilidade: Ler de buffer em testes, de arquivo em produção.
- Composição: Readers podem ser encadeados (buffered, limited, etc.).
- Processamento de streams: Ler dados incrementalmente sem carregar tudo na memória.
Exemplo Prático
Leitura Linha por Linha
const std = @import("std");
fn contarLinhas(reader: anytype) !usize {
var linhas: usize = 0;
while (true) {
_ = reader.readUntilDelimiterOrEof('\n') catch |err| switch (err) {
error.StreamTooLong => continue,
else => return err,
} orelse break;
linhas += 1;
}
return linhas;
}
pub fn main() !void {
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();
var buffer: [4096]u8 = undefined;
var linhas: usize = 0;
while (true) {
const linha = reader.readUntilDelimiterOrEof(&buffer, '\n') catch continue;
if (linha == null) break;
linhas += 1;
}
std.debug.print("Total de linhas: {}\n", .{linhas});
}
const std = @import("std");
fn lerExatamente(reader: anytype, n: usize, buffer: []u8) ![]u8 {
if (n > buffer.len) return error.BufferPequeno;
const lidos = try reader.readAll(buffer[0..n]);
if (lidos < n) return error.FimPrematuro;
return buffer[0..n];
}
test "ler de buffer em memória" {
const dados = "Hello, Zig Brasil!";
var stream = std.io.fixedBufferStream(dados);
const reader = stream.reader();
var buffer: [5]u8 = undefined;
const resultado = try lerExatamente(reader, 5, &buffer);
try std.testing.expectEqualStrings("Hello", resultado);
}
const std = @import("std");
pub fn main() !void {
const arquivo = try std.fs.cwd().openFile("grande.bin", .{});
defer arquivo.close();
// Buffered reader reduz syscalls de leitura
var buf_reader = std.io.bufferedReader(arquivo.reader());
const reader = buf_reader.reader();
var total: u64 = 0;
var buffer: [4096]u8 = undefined;
while (true) {
const n = try reader.read(&buffer);
if (n == 0) break; // EOF
total += n;
}
std.debug.print("Total lido: {} bytes\n", .{total});
}
Readers Comuns na std lib
| Reader | Descrição |
|---|
std.io.getStdIn().reader() | Entrada padrão (stdin) |
file.reader() | Leitura de arquivo |
stream.reader() | Leitura de fixedBufferStream |
std.io.bufferedReader(r) | Reader com buffer |
std.io.limitedReader(r, n) | Reader que limita bytes lidos |
Métodos do Reader
| Método | Descrição |
|---|
read(buffer) | Ler até buffer.len bytes |
readAll(buffer) | Ler exatamente buffer.len bytes |
readByte() | Ler um único byte |
readUntilDelimiterOrEof(buf, delim) | Ler até delimitador ou EOF |
skipBytes(n) | Pular n bytes |
readInt(T) | Ler inteiro com endianness |
Armadilhas Comuns
- read retorna 0 no EOF: Sempre verifique se
read() retornou 0 — isso indica fim dos dados. - read pode retornar menos bytes: Uma chamada a
read() pode retornar menos bytes do que o buffer. Use readAll() quando precisar de quantidade exata. - Buffer insuficiente:
readUntilDelimiterOrEof retorna erro se a linha exceder o buffer. - Performance sem buffer: Sem
bufferedReader, cada readByte() gera uma syscall.
Termos Relacionados
Tutoriais Relacionados