std.fs em Zig — Referência e Exemplos

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

Tutoriais e Receitas Relacionados

Continue aprendendo Zig

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