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
- Criar Diretórios — Crie diretórios antes de listar
- Verificar se Arquivo Existe — Verifique existência
- Deletar Arquivos e Diretórios — Remova itens listados
- Manipulação de Caminhos — Trabalhe com caminhos