std.fs — Sistema de Arquivos
O módulo std.fs fornece uma interface portável para operações com o sistema de arquivos. Ele permite abrir, criar, ler e escrever arquivos, manipular diretórios, trabalhar com caminhos e realizar operações atômicas — tudo com tratamento explícito de erros.
Visão Geral
O design do std.fs segue princípios fundamentais do Zig:
- Sem alocações ocultas: Caminhos são passados como slices, sem construir strings internamente
- Erros explícitos: Todas as operações que podem falhar retornam error unions
- Portabilidade: Funciona em Linux, macOS, Windows e outros sistemas suportados
- Segurança: Preferência por operações baseadas em descritores de diretório (
Dir) em vez de caminhos absolutos
const std = @import("std");
const fs = std.fs;
Tipos Principais
fs.File
Representa um arquivo aberto. Fornece métodos para leitura, escrita, posicionamento e metadados.
fs.Dir
Representa um diretório aberto. Usado para abrir arquivos relativos, iterar entradas e realizar operações de diretório.
fs.path
Submódulo com funções utilitárias para manipulação de caminhos de arquivo.
Funções Principais
fs.cwd()
pub fn cwd() Dir
Retorna um Dir representando o diretório de trabalho atual do processo.
fs.openFileAbsolute
pub fn openFileAbsolute(absolute_path: []const u8, flags: File.OpenFlags) File.OpenError!File
Abre um arquivo usando caminho absoluto.
fs.createFileAbsolute
pub fn createFileAbsolute(absolute_path: []const u8, flags: File.CreateFlags) File.OpenError!File
Cria (ou trunca) um arquivo usando caminho absoluto.
fs.deleteFileAbsolute
pub fn deleteFileAbsolute(absolute_path: []const u8) File.OpenError!void
Remove um arquivo usando caminho absoluto.
Exemplo 1: Operações Básicas com Arquivos
const std = @import("std");
pub fn main() !void {
const cwd = std.fs.cwd();
// Criar e escrever em um arquivo
{
const arquivo = try cwd.createFile("exemplo.txt", .{});
defer arquivo.close();
try arquivo.writeAll("Primeira linha\n");
try arquivo.writeAll("Segunda linha\n");
try arquivo.writeAll("Terceira linha\n");
}
// Ler o arquivo inteiro
var gpa = std.heap.GeneralPurposeAllocator(.{}){};
defer _ = gpa.deinit();
const allocator = gpa.allocator();
const conteudo = try cwd.readFileAlloc(allocator, "exemplo.txt", 1024 * 1024);
defer allocator.free(conteudo);
std.debug.print("Conteúdo do arquivo:\n{s}\n", .{conteudo});
// Obter informações do arquivo
const arquivo = try cwd.openFile("exemplo.txt", .{});
defer arquivo.close();
const stat = try arquivo.stat();
std.debug.print("Tamanho: {d} bytes\n", .{stat.size});
// Remover o arquivo
try cwd.deleteFile("exemplo.txt");
}
Exemplo 2: Listando Diretórios
const std = @import("std");
pub fn main() !void {
var gpa = std.heap.GeneralPurposeAllocator(.{}){};
defer _ = gpa.deinit();
const allocator = gpa.allocator();
const cwd = std.fs.cwd();
// Abrir diretório para iteração
var dir = try cwd.openDir(".", .{ .iterate = true });
defer dir.close();
var iter = dir.iterate();
var contagem: usize = 0;
std.debug.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 => "???",
};
std.debug.print(" [{s}] {s}\n", .{ tipo, entrada.name });
contagem += 1;
}
std.debug.print("\nTotal: {d} entradas\n", .{contagem});
_ = allocator;
}
Exemplo 3: Manipulação de Caminhos
const std = @import("std");
pub fn main() !void {
// Juntar componentes de caminho
var buf: [std.fs.max_path_bytes]u8 = undefined;
const caminho = try std.fmt.bufPrint(&buf, "{s}/{s}", .{ "/home/usuario", "documentos/arquivo.txt" });
std.debug.print("Caminho: {s}\n", .{caminho});
// Usando std.fs.path
const dirname = std.fs.path.dirname("/home/usuario/arquivo.txt");
const basename = std.fs.path.basename("/home/usuario/arquivo.txt");
const extensao = std.fs.path.extension("arquivo.txt");
std.debug.print("Diretório: {s}\n", .{dirname orelse "(nenhum)"});
std.debug.print("Nome: {s}\n", .{basename});
std.debug.print("Extensão: {s}\n", .{extensao});
}
Padrões Comuns
Abertura Segura com defer
Sempre use defer para garantir que arquivos e diretórios sejam fechados:
const arquivo = try std.fs.cwd().openFile("dados.txt", .{});
defer arquivo.close();
// usar arquivo...
Criação de Diretórios
// Criar um diretório
try std.fs.cwd().makeDir("novo_dir");
// Criar diretórios recursivamente
try std.fs.cwd().makePath("a/b/c");
Verificação de Existência
// Verificar se arquivo existe (tentando abri-lo)
if (std.fs.cwd().openFile("config.txt", .{})) |arquivo| {
arquivo.close();
// Arquivo existe
} else |_| {
// Arquivo não existe ou erro de permissão
}
Operações Baseadas em Dir
Preferir operações relativas a um Dir em vez de caminhos absolutos é mais seguro e portável:
const base = try std.fs.cwd().openDir("projeto", .{});
defer base.close();
// Operações relativas ao diretório base
const arquivo = try base.openFile("src/main.zig", .{});
defer arquivo.close();
Módulos Relacionados
- std.fs.cwd() — Diretório atual e operações
- std.fs.File — Tipo File e suas operações
- std.fs.path — Utilitários de caminhos
- std.fs.Dir — Tipo Dir e iteração
- std.io — Interfaces de I/O usadas por File