std.fs.Dir em Zig — Referência e Exemplos

std.fs.Dir — Tipo Dir e Iteração

O tipo std.fs.Dir representa um descritor de diretório aberto. Ele é a base para operações de sistema de arquivos no Zig, oferecendo métodos para abrir arquivos relativos, iterar entradas, criar subdiretórios e realizar operações recursivas.

Visão Geral

Diferente de usar caminhos absolutos como strings, trabalhar com Dir é mais seguro e eficiente. Cada operação é relativa ao diretório representado pelo Dir, evitando condições de corrida com mudanças de diretório de trabalho.

const std = @import("std");

// Obter o diretório de trabalho atual
const cwd = std.fs.cwd();

// Abrir um subdiretório
var dir = try cwd.openDir("src", .{ .iterate = true });
defer dir.close();

Tipos e Estruturas

OpenDirOptions

pub const OpenDirOptions = struct {
    iterate: bool = false,     // Permitir iteração
    access_sub_paths: bool = true, // Permitir acesso a subcaminhos
    no_follow: bool = false,   // Não seguir links simbólicos
};

Entry (Entrada de Diretório)

pub const Entry = struct {
    name: []const u8,
    kind: Kind,
};

pub const Kind = enum {
    block_device,
    character_device,
    directory,
    named_pipe,
    sym_link,
    file,
    unix_domain_socket,
    whiteout,
    unknown,
};

Métodos Principais

Abertura e Criação

pub fn openDir(self: Dir, sub_path: []const u8, flags: OpenDirOptions) !Dir
pub fn openFile(self: Dir, sub_path: []const u8, flags: File.OpenFlags) !File
pub fn createFile(self: Dir, sub_path: []const u8, flags: File.CreateFlags) !File
pub fn makeDir(self: Dir, sub_path: []const u8) !void
pub fn makePath(self: Dir, sub_path: []const u8) !void

Remoção

pub fn deleteFile(self: Dir, sub_path: []const u8) !void
pub fn deleteDir(self: Dir, sub_path: []const u8) !void
pub fn deleteTree(self: Dir, sub_path: []const u8) !void

Iteração

pub fn iterate(self: Dir) Iterator
pub fn walk(self: Dir, allocator: Allocator) !Walker

Utilitários

pub fn realpath(self: Dir, pathname: []const u8, buf: []u8) ![]u8
pub fn readFileAlloc(self: Dir, allocator: Allocator, file_path: []const u8, max_bytes: usize) ![]u8
pub fn rename(self: Dir, old: []const u8, new: []const u8) !void
pub fn close(self: *Dir) void

Exemplo 1: Listando Conteúdo de Diretório

const std = @import("std");

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

    var iter = dir.iterate();

    var num_arquivos: usize = 0;
    var num_dirs: usize = 0;
    var num_outros: usize = 0;

    std.debug.print("Conteúdo do diretório atual:\n\n", .{});

    while (try iter.next()) |entrada| {
        const icone = switch (entrada.kind) {
            .file => {
                num_arquivos += 1;
                break :blk "[ARQ]";
            },
            .directory => {
                num_dirs += 1;
                break :blk "[DIR]";
            },
            .sym_link => {
                num_outros += 1;
                break :blk "[LNK]";
            },
            else => {
                num_outros += 1;
                break :blk "[???]";
            },
        };
        _ = icone;

        const tipo: []const u8 = switch (entrada.kind) {
            .file => "[ARQ]",
            .directory => "[DIR]",
            .sym_link => "[LNK]",
            else => "[???]",
        };
        std.debug.print("  {s} {s}\n", .{ tipo, entrada.name });
    }

    std.debug.print("\nTotal: {d} arquivos, {d} diretórios, {d} outros\n", .{
        num_arquivos, num_dirs, num_outros,
    });
}

Exemplo 2: Busca Recursiva com Walker

O Walker permite percorrer toda a árvore de diretórios:

const std = @import("std");

pub fn main() !void {
    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 walker = try dir.walk(allocator);
    defer walker.deinit();

    var contagem_zig: usize = 0;

    std.debug.print("Arquivos .zig encontrados:\n", .{});
    while (try walker.next()) |entrada| {
        if (entrada.kind != .file) continue;

        const ext = std.fs.path.extension(entrada.basename);
        if (std.mem.eql(u8, ext, ".zig")) {
            contagem_zig += 1;
            std.debug.print("  {s}\n", .{entrada.path});
        }
    }

    std.debug.print("\nTotal: {d} arquivos .zig\n", .{contagem_zig});
}

Exemplo 3: Criando Estrutura de Projeto

const std = @import("std");

fn criarEstruturaProjeto(nome: []const u8) !void {
    const cwd = std.fs.cwd();

    // Criar diretório raiz e subdiretórios
    try cwd.makePath(nome);
    const diretorios = [_][]const u8{ "src", "tests", "docs", "lib" };

    for (diretorios) |subdir| {
        var buf: [256]u8 = undefined;
        const caminho = try std.fmt.bufPrint(&buf, "{s}/{s}", .{ nome, subdir });
        try cwd.makePath(caminho);
        std.debug.print("Criado: {s}/\n", .{caminho});
    }

    // Criar arquivo principal
    {
        var buf: [256]u8 = undefined;
        const main_path = try std.fmt.bufPrint(&buf, "{s}/src/main.zig", .{nome});
        const f = try cwd.createFile(main_path, .{});
        defer f.close();
        try f.writer().print(
            \\const std = @import("std");
            \\
            \\pub fn main() !void {{
            \\    std.debug.print("Projeto {s} iniciado!\n", .{{}});
            \\}}
            \\
        , .{nome});
        std.debug.print("Criado: {s}\n", .{main_path});
    }

    // Criar build.zig
    {
        var buf: [256]u8 = undefined;
        const build_path = try std.fmt.bufPrint(&buf, "{s}/build.zig", .{nome});
        const f = try cwd.createFile(build_path, .{});
        defer f.close();
        try f.writeAll("// Build configuration\n");
        std.debug.print("Criado: {s}\n", .{build_path});
    }
}

pub fn main() !void {
    try criarEstruturaProjeto("meu_projeto");
    std.debug.print("\nEstrutura criada com sucesso!\n", .{});

    // Limpar para o exemplo
    try std.fs.cwd().deleteTree("meu_projeto");
}

Padrões Comuns

Iteração Segura com defer

var dir = try base.openDir("subdir", .{ .iterate = true });
defer dir.close();

var iter = dir.iterate();
while (try iter.next()) |entry| {
    // processar entry
}

Filtrar por Tipo

while (try iter.next()) |entry| {
    if (entry.kind == .file) {
        // Processar apenas arquivos
    }
}

Operações Aninhadas

var projeto = try cwd.openDir("projeto", .{});
defer projeto.close();

var src = try projeto.openDir("src", .{ .iterate = true });
defer src.close();

const arquivo = try src.openFile("main.zig", .{});
defer arquivo.close();

Deletar Tudo Recursivamente

try dir.deleteTree("pasta_temporaria");

Módulos Relacionados

Tutoriais e Receitas Relacionados

Continue aprendendo Zig

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