Como Listar Conteúdo de Diretório em Zig

Como Listar Conteúdo de Diretório em Zig

Listar o conteúdo de um diretório é fundamental para muitas operações como busca de arquivos, organização de dados e scripts de automação. Zig fornece a API std.fs.Dir com iteradores eficientes.

Listagem Básica

Use iterate() para iterar sobre as entradas de um diretório.

const std = @import("std");

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

    // Abrir diretório atual
    var dir = try std.fs.cwd().openDir(".", .{ .iterate = true });
    defer dir.close();

    var iter = dir.iterate();

    try stdout.print("Conteúdo do diretório atual:\n", .{});
    while (try iter.next()) |entrada| {
        const tipo = switch (entrada.kind) {
            .file => "ARQ",
            .directory => "DIR",
            .sym_link => "LNK",
            else => "???",
        };
        try stdout.print("  [{s}] {s}\n", .{ tipo, entrada.name });
    }
}

Filtrar por Tipo de Entrada

Filtre a listagem para mostrar apenas arquivos ou apenas diretórios.

const std = @import("std");

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

    var dir = try std.fs.cwd().openDir(".", .{ .iterate = true });
    defer dir.close();

    // Listar apenas arquivos
    try stdout.print("Arquivos:\n", .{});
    var iter1 = dir.iterate();
    while (try iter1.next()) |entrada| {
        if (entrada.kind == .file) {
            try stdout.print("  {s}\n", .{entrada.name});
        }
    }

    // Resetar iterador para listar diretórios
    dir.reset();
    try stdout.print("\nDiretórios:\n", .{});
    var iter2 = dir.iterate();
    while (try iter2.next()) |entrada| {
        if (entrada.kind == .directory) {
            try stdout.print("  {s}/\n", .{entrada.name});
        }
    }
}

Filtrar por Extensão

const std = @import("std");

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

    var dir = try std.fs.cwd().openDir(".", .{ .iterate = true });
    defer dir.close();

    const extensao = ".zig";

    try stdout.print("Arquivos {s}:\n", .{extensao});
    var iter = dir.iterate();
    while (try iter.next()) |entrada| {
        if (entrada.kind == .file and std.mem.endsWith(u8, entrada.name, extensao)) {
            try stdout.print("  {s}\n", .{entrada.name});
        }
    }
}

Listagem Recursiva com walk

Use walk() para percorrer diretórios recursivamente.

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();

    var dir = try std.fs.cwd().openDir(".", .{ .iterate = true });
    defer dir.close();

    // Walker recursivo
    var walker = try dir.walk(allocator);
    defer walker.deinit();

    try stdout.print("Todos os arquivos (recursivo):\n", .{});
    while (try walker.next()) |entrada| {
        const tipo = switch (entrada.kind) {
            .file => "ARQ",
            .directory => "DIR",
            .sym_link => "LNK",
            else => "???",
        };
        try stdout.print("  [{s}] {s}\n", .{ tipo, entrada.path });
    }
}

Coletar Nomes em ArrayList

Armazene os nomes dos arquivos em uma lista para processamento posterior.

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();

    var dir = try std.fs.cwd().openDir(".", .{ .iterate = true });
    defer dir.close();

    var arquivos = std.ArrayList([]const u8).init(allocator);
    defer {
        for (arquivos.items) |nome| allocator.free(nome);
        arquivos.deinit();
    }

    var iter = dir.iterate();
    while (try iter.next()) |entrada| {
        if (entrada.kind == .file) {
            const nome = try allocator.dupe(u8, entrada.name);
            try arquivos.append(nome);
        }
    }

    try stdout.print("Total de arquivos: {d}\n", .{arquivos.items.len});
    for (arquivos.items) |nome| {
        try stdout.print("  - {s}\n", .{nome});
    }
}

Obter Informações Detalhadas

Combine a listagem com stat para obter metadados como tamanho e timestamps.

const std = @import("std");

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

    var dir = try std.fs.cwd().openDir(".", .{ .iterate = true });
    defer dir.close();

    try stdout.print("{s:<30} {s:>10} {s}\n", .{ "Nome", "Tamanho", "Tipo" });
    try stdout.print("{s}\n", .{"-" ** 50});

    var iter = dir.iterate();
    while (try iter.next()) |entrada| {
        if (entrada.kind == .file) {
            // Obter stat do arquivo
            const stat = dir.statFile(entrada.name) catch continue;
            const tamanho_kb = stat.size / 1024;
            try stdout.print("{s:<30} {d:>7} KB  ARQ\n", .{ entrada.name, tamanho_kb });
        } else if (entrada.kind == .directory) {
            try stdout.print("{s:<30} {s:>10}  DIR\n", .{ entrada.name, "-" });
        }
    }
}

Exemplo Prático: Contar Arquivos por Extensão

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();

    var dir = try std.fs.cwd().openDir(".", .{ .iterate = true });
    defer dir.close();

    // Mapa de extensões para contagem
    var contagem = std.StringHashMap(u32).init(allocator);
    defer {
        var it = contagem.iterator();
        while (it.next()) |entry| {
            allocator.free(entry.key_ptr.*);
        }
        contagem.deinit();
    }

    var walker = try dir.walk(allocator);
    defer walker.deinit();

    while (try walker.next()) |entrada| {
        if (entrada.kind != .file) continue;

        const nome = entrada.basename;
        const ext = if (std.mem.lastIndexOfScalar(u8, nome, '.')) |pos|
            nome[pos..]
        else
            "(sem extensão)";

        const chave = try allocator.dupe(u8, ext);
        const resultado = try contagem.getOrPut(chave);
        if (resultado.found_existing) {
            allocator.free(chave);
            resultado.value_ptr.* += 1;
        } else {
            resultado.value_ptr.* = 1;
        }
    }

    try stdout.print("Arquivos por extensão:\n", .{});
    var it = contagem.iterator();
    while (it.next()) |entry| {
        try stdout.print("  {s:<15} {d} arquivo(s)\n", .{ entry.key_ptr.*, entry.value_ptr.* });
    }
}

Veja Também

Continue aprendendo Zig

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