Introdução
Manipular caminhos de arquivo (paths) é essencial para qualquer programa que trabalhe com o sistema de arquivos. Zig oferece std.fs.path com funções para juntar, separar, normalizar e extrair componentes de caminhos de forma portável entre sistemas operacionais.
Nesta receita, você aprenderá as operações mais comuns com caminhos.
Pré-requisitos
- Zig instalado (versão 0.13+). Veja o guia de instalação
- Conhecimento básico de Zig. Consulte a introdução ao Zig
Juntar Componentes de Caminho
const std = @import("std");
const path = std.fs.path;
pub fn main() !void {
var gpa = std.heap.GeneralPurposeAllocator(.{}){};
defer _ = gpa.deinit();
const allocator = gpa.allocator();
// Juntar componentes de caminho
const resultado = try path.join(allocator, &[_][]const u8{
"/home",
"usuario",
"projetos",
"meu-app",
"src",
"main.zig",
});
defer allocator.free(resultado);
std.debug.print("Caminho: {s}\n", .{resultado});
// Juntar com diretório relativo
const relativo = try path.join(allocator, &[_][]const u8{
"src",
"modules",
"parser.zig",
});
defer allocator.free(relativo);
std.debug.print("Relativo: {s}\n", .{relativo});
}
Extrair Componentes de um Caminho
const std = @import("std");
const path = std.fs.path;
pub fn main() !void {
const caminho = "/home/usuario/projeto/src/main.zig";
// Nome do diretório (dirname)
const dir = path.dirname(caminho);
std.debug.print("Diretório: {s}\n", .{dir orelse "(vazio)"});
// Nome do arquivo (basename)
const base = path.basename(caminho);
std.debug.print("Arquivo: {s}\n", .{base});
// Extensão
const ext = path.extension(caminho);
std.debug.print("Extensão: {s}\n", .{ext});
// Stem (nome sem extensão)
const stem = path.stem(caminho);
std.debug.print("Stem: {s}\n", .{stem});
// Verificar se é absoluto
std.debug.print("É absoluto? {}\n", .{path.isAbsolute(caminho)});
// Componentes separados
std.debug.print("\nComponentes:\n", .{});
var it = std.mem.splitScalar(u8, caminho, '/');
while (it.next()) |componente| {
if (componente.len > 0) {
std.debug.print(" {s}\n", .{componente});
}
}
}
Saída esperada
Diretório: /home/usuario/projeto/src
Arquivo: main.zig
Extensão: .zig
Stem: main
É absoluto? true
Componentes:
home
usuario
projeto
src
main.zig
Trocar Extensão de Arquivo
const std = @import("std");
const path = std.fs.path;
fn trocarExtensao(allocator: std.mem.Allocator, caminho: []const u8, nova_ext: []const u8) ![]u8 {
const dir = path.dirname(caminho);
const stem_name = path.stem(caminho);
if (dir) |d| {
return std.fmt.allocPrint(allocator, "{s}/{s}{s}", .{ d, stem_name, nova_ext });
} else {
return std.fmt.allocPrint(allocator, "{s}{s}", .{ stem_name, nova_ext });
}
}
pub fn main() !void {
var gpa = std.heap.GeneralPurposeAllocator(.{}){};
defer _ = gpa.deinit();
const allocator = gpa.allocator();
const arquivos = [_][]const u8{
"projeto/main.zig",
"dados/config.json",
"src/modulo.zig",
"relatorio.txt",
};
for (&arquivos) |arq| {
const novo = try trocarExtensao(allocator, arq, ".bak");
defer allocator.free(novo);
std.debug.print("{s} -> {s}\n", .{ arq, novo });
}
}
Resolver Caminho Absoluto
const std = @import("std");
pub fn main() !void {
var gpa = std.heap.GeneralPurposeAllocator(.{}){};
defer _ = gpa.deinit();
const allocator = gpa.allocator();
// Obter diretório de trabalho atual
const cwd = try std.fs.cwd().realpathAlloc(allocator, ".");
defer allocator.free(cwd);
std.debug.print("CWD: {s}\n", .{cwd});
// Construir caminho absoluto
const absoluto = try std.fs.path.join(allocator, &[_][]const u8{ cwd, "src", "main.zig" });
defer allocator.free(absoluto);
std.debug.print("Absoluto: {s}\n", .{absoluto});
}
Exemplo Prático: Organizar Arquivos por Extensão
const std = @import("std");
const path = std.fs.path;
pub fn main() !void {
var gpa = std.heap.GeneralPurposeAllocator(.{}){};
defer _ = gpa.deinit();
const allocator = gpa.allocator();
const arquivos = [_][]const u8{
"foto1.jpg",
"documento.pdf",
"main.zig",
"foto2.png",
"notas.txt",
"build.zig",
"relatorio.pdf",
"avatar.jpg",
};
// Agrupar por extensão
var grupos = std.StringHashMap(std.ArrayList([]const u8)).init(allocator);
defer {
var it = grupos.valueIterator();
while (it.next()) |lista| lista.deinit();
grupos.deinit();
}
for (&arquivos) |arq| {
const ext = path.extension(arq);
const result = try grupos.getOrPut(ext);
if (!result.found_existing) {
result.value_ptr.* = std.ArrayList([]const u8).init(allocator);
}
try result.value_ptr.append(arq);
}
// Exibir grupos
var it = grupos.iterator();
while (it.next()) |entry| {
std.debug.print("\n{s}:\n", .{entry.key_ptr.*});
for (entry.value_ptr.items) |arq| {
std.debug.print(" {s}\n", .{arq});
}
}
}
Dicas e Boas Práticas
Use
std.fs.path.join: Nunca concatene paths manualmente com/– usejoinpara portabilidade.dirnameretorna optional: Pode sernullpara caminhos sem diretório.A extensão inclui o ponto:
extension("main.zig")retorna".zig", não"zig".Normalize caminhos: Use
path.joinpara remover componentes redundantes como./e../.
Receitas Relacionadas
- Ler Conteúdo de Arquivo - Ler arquivos
- Criar Diretórios - Criar diretórios
- Listar Conteúdo de Diretório - Enumerar arquivos
- Criar Arquivos Temporários - Temporários