---
title: "Como Ler Arquivo Linha por Linha em Zig"
url: "https://ziglang.com.br/receitas/como-ler-arquivo-linha-por-linha-em-zig/"
markdown_url: "https://ziglang.com.br/receitas/como-ler-arquivo-linha-por-linha-em-zig.MD"
description: "Aprenda a ler e processar arquivos linha por linha em Zig usando reader e buffers. Ideal para arquivos grandes e processamento de texto."
date: "2026-02-21"
author: "Zig Brasil"
---

# Como Ler Arquivo Linha por Linha em Zig

Aprenda a ler e processar arquivos linha por linha em Zig usando reader e buffers. Ideal para arquivos grandes e processamento de texto.


# Como Ler Arquivo Linha por Linha em Zig

Ler um arquivo linha por linha é essencial quando você precisa processar arquivos grandes sem carregar tudo na memória, ou quando quer processar cada linha individualmente (como em logs, CSV ou configurações).

## Leitura Básica Linha por Linha

Use `reader().readUntilDelimiterOrEof` para ler uma linha por vez.

```zig
const std = @import("std");

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

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

    // Criar buffered reader para melhor desempenho
    var buf_reader = std.io.bufferedReader(arquivo.reader());
    const reader = buf_reader.reader();

    var linha_buf: [4096]u8 = undefined;
    var numero_linha: u32 = 0;

    while (reader.readUntilDelimiterOrEof(&linha_buf, '\n')) |linha_opt| {
        const linha = linha_opt orelse break;
        numero_linha += 1;
        // Remover \r se existir (Windows line endings)
        const limpa = std.mem.trimRight(u8, linha, "\r");
        try stdout.print("{d:>4}: {s}\n", .{ numero_linha, limpa });
    } else |err| {
        return err;
    }

    try stdout.print("\nTotal: {d} linhas\n", .{numero_linha});
}
```

## Leitura com Alocação Dinâmica por Linha

Para linhas de tamanho arbitrário, use `readUntilDelimiterAlloc`.

```zig
const std = @import("std");

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

    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 numero_linha: u32 = 0;
    while (true) {
        const linha = reader.readUntilDelimiterAlloc(allocator, '\n', 1024 * 1024) catch |err| {
            if (err == error.EndOfStream) break;
            return err;
        };
        defer allocator.free(linha);

        numero_linha += 1;
        const limpa = std.mem.trimRight(u8, linha, "\r");
        try stdout.print("{d}: {s}\n", .{ numero_linha, limpa });
    }
}
```

## Coletar Todas as Linhas

Armazene todas as linhas em um ArrayList para processamento posterior.

```zig
const std = @import("std");

fn lerTodasLinhas(allocator: std.mem.Allocator, caminho: []const u8) !std.ArrayList([]u8) {
    const arquivo = try std.fs.cwd().openFile(caminho, .{});
    defer arquivo.close();

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

    var linhas = std.ArrayList([]u8).init(allocator);
    errdefer {
        for (linhas.items) |linha| allocator.free(linha);
        linhas.deinit();
    }

    while (true) {
        const linha = reader.readUntilDelimiterAlloc(allocator, '\n', 1024 * 1024) catch |err| {
            if (err == error.EndOfStream) break;
            return err;
        };
        const limpa = std.mem.trimRight(u8, linha, "\r");
        if (limpa.len < linha.len) {
            // Realocar sem o \r
            const nova = try allocator.dupe(u8, limpa);
            allocator.free(linha);
            try linhas.append(nova);
        } else {
            try linhas.append(linha);
        }
    }

    return linhas;
}

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

    var linhas = try lerTodasLinhas(allocator, "dados.txt");
    defer {
        for (linhas.items) |linha| allocator.free(linha);
        linhas.deinit();
    }

    try stdout.print("Total de linhas: {d}\n", .{linhas.items.len});
    for (linhas.items, 0..) |linha, i| {
        try stdout.print("  [{d}] \"{s}\"\n", .{ i, linha });
    }
}
```

## Processar Linhas com Filtro

```zig
const std = @import("std");

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

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

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

    var linha_buf: [8192]u8 = undefined;
    var erros: u32 = 0;
    var avisos: u32 = 0;

    while (reader.readUntilDelimiterOrEof(&linha_buf, '\n')) |linha_opt| {
        const linha = linha_opt orelse break;

        if (std.mem.indexOf(u8, linha, "[ERROR]") != null) {
            erros += 1;
            try stdout.print("ERRO: {s}\n", .{linha});
        } else if (std.mem.indexOf(u8, linha, "[WARN]") != null) {
            avisos += 1;
        }
    } else |err| {
        return err;
    }

    try stdout.print("\nResumo: {d} erros, {d} avisos\n", .{ erros, avisos });
}
```

## Exemplo Prático: Parser de Arquivo de Configuração

```zig
const std = @import("std");

const Config = struct {
    entries: std.StringHashMap([]const u8),
    allocator: std.mem.Allocator,

    fn init(allocator: std.mem.Allocator) Config {
        return .{
            .entries = std.StringHashMap([]const u8).init(allocator),
            .allocator = allocator,
        };
    }

    fn deinit(self: *Config) void {
        var it = self.entries.iterator();
        while (it.next()) |entry| {
            self.allocator.free(entry.key_ptr.*);
            self.allocator.free(entry.value_ptr.*);
        }
        self.entries.deinit();
    }

    fn get(self: *const Config, chave: []const u8) ?[]const u8 {
        return self.entries.get(chave);
    }
};

fn carregarConfig(allocator: std.mem.Allocator, caminho: []const u8) !Config {
    const arquivo = try std.fs.cwd().openFile(caminho, .{});
    defer arquivo.close();

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

    var config = Config.init(allocator);
    errdefer config.deinit();

    var linha_buf: [4096]u8 = undefined;
    while (reader.readUntilDelimiterOrEof(&linha_buf, '\n')) |linha_opt| {
        const linha_raw = linha_opt orelse break;
        const linha = std.mem.trim(u8, std.mem.trimRight(u8, linha_raw, "\r"), " \t");

        // Ignorar linhas vazias e comentários
        if (linha.len == 0 or linha[0] == '#' or linha[0] == ';') continue;

        // Buscar separador '='
        const sep = std.mem.indexOf(u8, linha, "=") orelse continue;

        const chave = std.mem.trim(u8, linha[0..sep], " \t");
        const valor = std.mem.trim(u8, linha[sep + 1 ..], " \t");

        const chave_dup = try allocator.dupe(u8, chave);
        const valor_dup = try allocator.dupe(u8, valor);
        try config.entries.put(chave_dup, valor_dup);
    } else |err| {
        return err;
    }

    return config;
}

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

    var config = try carregarConfig(allocator, "app.conf");
    defer config.deinit();

    // Acessar valores
    if (config.get("host")) |host| {
        try stdout.print("Host: {s}\n", .{host});
    }
    if (config.get("porta")) |porta| {
        try stdout.print("Porta: {s}\n", .{porta});
    }
}
```

## Veja Também

- [Ler Conteúdo de Arquivo](/receitas/zig-ler-arquivo/) — Leia arquivo completo
- [Dividir (Split) Strings](/receitas/zig-split-string/) — Processe cada linha
- [Remover Espaços (Trim)](/receitas/zig-trim-string/) — Limpe linhas lidas
- [HashMap e StringHashMap](/receitas/zig-hashmap-uso/) — Armazene dados parseados
