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
- std.fs — Visão geral do sistema de arquivos
- std.fs.cwd() — Diretório de trabalho atual
- std.fs.File — Tipo File retornado por openFile
- std.fs.path — Utilitários de caminhos
- std.mem.Allocator — Alocador usado por walk()