getStdOut, getStdErr, getStdIn — Fluxos Padrão
As funções getStdOut(), getStdErr() e getStdIn() fornecem acesso aos três fluxos padrão de I/O do processo: saída padrão, erro padrão e entrada padrão. Estes são os pontos de entrada mais comuns para interação com o terminal.
Visão Geral
Todo processo em sistemas Unix e Windows possui três descritores de arquivo padrão:
- stdout (fd 1): Saída padrão para dados normais do programa
- stderr (fd 2): Saída de erro para mensagens de diagnóstico e log
- stdin (fd 0): Entrada padrão para receber dados do usuário ou de pipes
const std = @import("std");
const stdout = std.io.getStdOut();
const stderr = std.io.getStdErr();
const stdin = std.io.getStdIn();
Assinaturas
pub fn getStdOut() std.fs.File
pub fn getStdErr() std.fs.File
pub fn getStdIn() std.fs.File
Todas retornam um std.fs.File, que oferece métodos .writer() e .reader() para obter as respectivas interfaces de I/O.
Diferença entre stdout e stderr
A separação entre stdout e stderr é fundamental:
- stdout: Dados de saída do programa (resultado, conteúdo gerado). Pode ser redirecionado com
>no shell. - stderr: Mensagens de erro, avisos e informações de diagnóstico. Permanece no terminal mesmo com redirecionamento.
# No shell, stdout vai para o arquivo, stderr permanece no terminal
./meu_programa > saida.txt
Exemplo 1: Escrita em stdout e stderr
const std = @import("std");
pub fn main() !void {
const stdout = std.io.getStdOut().writer();
const stderr = std.io.getStdErr().writer();
// Saída normal do programa — vai para stdout
try stdout.print("Processando {d} itens...\n", .{100});
// Simulação de processamento
for (0..100) |i| {
if (i % 25 == 0) {
// Mensagem de progresso — vai para stderr
try stderr.print("[INFO] Progresso: {d}%\n", .{i});
}
}
// Resultado — vai para stdout
try stdout.writeAll("Processamento concluído.\n");
// Aviso — vai para stderr
try stderr.writeAll("[AVISO] 3 itens foram ignorados.\n");
}
Exemplo 2: Leitura Interativa com stdin
const std = @import("std");
pub fn main() !void {
const stdin = std.io.getStdIn().reader();
const stdout = std.io.getStdOut().writer();
try stdout.writeAll("=== Calculadora Simples ===\n\n");
try stdout.writeAll("Digite o primeiro número: ");
var buf: [64]u8 = undefined;
const input1 = try stdin.readUntilDelimiterOrEof(&buf, '\n') orelse {
try stdout.writeAll("Entrada vazia.\n");
return;
};
const num1 = std.fmt.parseFloat(f64, input1) catch {
try stdout.print("'{s}' não é um número válido.\n", .{input1});
return;
};
try stdout.writeAll("Digite o segundo número: ");
const input2 = try stdin.readUntilDelimiterOrEof(&buf, '\n') orelse {
try stdout.writeAll("Entrada vazia.\n");
return;
};
const num2 = std.fmt.parseFloat(f64, input2) catch {
try stdout.print("'{s}' não é um número válido.\n", .{input2});
return;
};
try stdout.print("\nResultados:\n", .{});
try stdout.print(" {d} + {d} = {d}\n", .{ num1, num2, num1 + num2 });
try stdout.print(" {d} - {d} = {d}\n", .{ num1, num2, num1 - num2 });
try stdout.print(" {d} * {d} = {d}\n", .{ num1, num2, num1 * num2 });
if (num2 != 0) {
try stdout.print(" {d} / {d} = {d:.4}\n", .{ num1, num2, num1 / num2 });
} else {
try stderr.writeAll("[ERRO] Divisão por zero!\n");
}
}
Exemplo 3: Programa de Filtro (stdin para stdout)
Programas de filtro leem de stdin e escrevem em stdout, como ferramentas Unix:
const std = @import("std");
pub fn main() !void {
const stdin = std.io.getStdIn().reader();
const stdout = std.io.getStdOut().writer();
const stderr = std.io.getStdErr().writer();
var buf_reader = std.io.bufferedReader(stdin);
const reader = buf_reader.reader();
var buf_writer = std.io.bufferedWriter(stdout);
const writer = buf_writer.writer();
var buf: [4096]u8 = undefined;
var linhas_total: usize = 0;
var linhas_filtradas: usize = 0;
// Filtrar apenas linhas que contêm "TODO"
while (reader.readUntilDelimiterOrEof(&buf, '\n')) |maybe_linha| {
if (maybe_linha) |linha| {
linhas_total += 1;
if (std.mem.indexOf(u8, linha, "TODO")) |_| {
linhas_filtradas += 1;
try writer.print("{s}\n", .{linha});
}
} else break;
} else |_| {}
try buf_writer.flush();
// Estatísticas para stderr (não poluem a saída filtrada)
try stderr.print("Linhas processadas: {d}\n", .{linhas_total});
try stderr.print("Linhas com TODO: {d}\n", .{linhas_filtradas});
}
Uso no shell:
cat codigo.zig | ./filtro_todo > todos.txt
Padrões Comuns
Debug Print vs stdout
O Zig oferece std.debug.print como atalho para escrita em stderr:
// Estas duas linhas são equivalentes:
std.debug.print("Debug: {d}\n", .{valor});
std.io.getStdErr().writer().print("Debug: {d}\n", .{valor}) catch {};
Note que std.debug.print ignora erros silenciosamente, enquanto o uso direto de stderr.writer().print() retorna o erro.
Verificação de Terminal
Você pode verificar se stdout é um terminal (TTY) ou está redirecionado:
const stdout_file = std.io.getStdOut();
if (stdout_file.supportsAnsiEscapeCodes()) {
// Terminal com suporte a cores — usar ANSI
try stdout_file.writer().writeAll("\x1b[32mSucesso!\x1b[0m\n");
} else {
// Redirecionado para arquivo — sem cores
try stdout_file.writer().writeAll("Sucesso!\n");
}
Padrão para Programas CLI
pub fn main() !void {
const stdout = std.io.getStdOut().writer();
const stderr = std.io.getStdErr().writer();
executar(stdout, stderr) catch |err| {
stderr.print("Erro fatal: {}\n", .{err}) catch {};
std.process.exit(1);
};
}
Módulos Relacionados
- std.io — Visão geral do módulo de I/O
- std.io.Writer — Interface Writer retornada por
.writer() - std.io.Reader — Interface Reader retornada por
.reader() - std.io Buffered — Buffering para melhor desempenho
- std.fs.File — Tipo File retornado por getStdOut/Err/In
- std.debug — debug.print como atalho para stderr