Como Verificar se Arquivo Existe em Zig

Como Verificar se Arquivo Existe em Zig

Verificar se um arquivo ou diretório existe antes de operar sobre ele é uma prática defensiva importante. Em Zig, isso pode ser feito de diferentes formas dependendo do que você precisa verificar.

Verificar com access

A forma mais direta é usar access, que verifica se o arquivo existe e se é acessível.

const std = @import("std");

pub fn main() !void {
    const stdout = std.io.getStdOut().writer();

    // Verificar se arquivo existe
    const existe = std.fs.cwd().access("exemplo.txt", .{});
    if (existe) |_| {
        try stdout.print("'exemplo.txt' existe e é acessível\n", .{});
    } else |_| {
        try stdout.print("'exemplo.txt' não existe ou não é acessível\n", .{});
    }
}

Função Utilitária: arquivoExiste

const std = @import("std");

fn arquivoExiste(caminho: []const u8) bool {
    std.fs.cwd().access(caminho, .{}) catch return false;
    return true;
}

fn arquivoExisteAbsoluto(caminho: []const u8) bool {
    std.fs.accessAbsolute(caminho, .{}) catch return false;
    return true;
}

pub fn main() !void {
    const stdout = std.io.getStdOut().writer();

    // Verificar diversos arquivos
    const caminhos = [_][]const u8{
        "build.zig",
        "src/main.zig",
        "inexistente.txt",
    };

    for (caminhos) |caminho| {
        const existe = arquivoExiste(caminho);
        try stdout.print("  {s:<25} -> {s}\n", .{
            caminho,
            if (existe) "EXISTE" else "NÃO EXISTE",
        });
    }

    // Verificar caminho absoluto
    const etc_existe = arquivoExisteAbsoluto("/etc/hosts");
    try stdout.print("  /etc/hosts -> {s}\n", .{if (etc_existe) "EXISTE" else "NÃO EXISTE"});
}

Verificar com statFile (Mais Informações)

Use statFile para obter informações detalhadas além da existência.

const std = @import("std");

fn verificarDetalhado(caminho: []const u8) !void {
    const stdout = std.io.getStdOut().writer();

    const stat = std.fs.cwd().statFile(caminho) catch |err| {
        switch (err) {
            error.FileNotFound => {
                try stdout.print("'{s}': não encontrado\n", .{caminho});
                return;
            },
            error.AccessDenied => {
                try stdout.print("'{s}': sem permissão\n", .{caminho});
                return;
            },
            else => return err,
        }
    };

    const tipo = switch (stat.kind) {
        .file => "arquivo",
        .directory => "diretório",
        .sym_link => "link simbólico",
        else => "outro",
    };

    try stdout.print("'{s}': {s}, {d} bytes\n", .{ caminho, tipo, stat.size });
}

pub fn main() !void {
    try verificarDetalhado("build.zig");
    try verificarDetalhado("src");
    try verificarDetalhado("inexistente.txt");
}

Verificar Tipo Específico

Determine se o caminho é um arquivo regular, diretório ou link simbólico.

const std = @import("std");

fn isArquivo(caminho: []const u8) bool {
    const stat = std.fs.cwd().statFile(caminho) catch return false;
    return stat.kind == .file;
}

fn isDiretorio(caminho: []const u8) bool {
    // Tentar abrir como diretório
    var dir = std.fs.cwd().openDir(caminho, .{}) catch return false;
    dir.close();
    return true;
}

pub fn main() !void {
    const stdout = std.io.getStdOut().writer();

    const caminhos = [_][]const u8{ "build.zig", "src", "inexistente" };

    for (caminhos) |caminho| {
        try stdout.print("{s:<20}: arquivo={}, diretório={}\n", .{
            caminho,
            isArquivo(caminho),
            isDiretorio(caminho),
        });
    }
}

Padrão: Abrir ou Criar

Na prática, muitas vezes é melhor simplesmente tentar a operação e tratar o erro, em vez de verificar antes.

const std = @import("std");

fn lerOuCriarConfig(allocator: std.mem.Allocator) ![]u8 {
    // Tentar ler o arquivo existente
    const arquivo = std.fs.cwd().openFile("config.ini", .{}) catch |err| {
        if (err == error.FileNotFound) {
            // Criar com valores padrão
            const padrao =
                \\[servidor]
                \\host = localhost
                \\porta = 8080
                \\
                \\[banco]
                \\url = sqlite://dados.db
            ;
            const arq = try std.fs.cwd().createFile("config.ini", .{});
            defer arq.close();
            try arq.writeAll(padrao);

            return allocator.dupe(u8, padrao);
        }
        return err;
    };
    defer arquivo.close();

    return arquivo.readToEndAlloc(allocator, 1024 * 1024);
}

pub fn main() !void {
    const stdout = std.io.getStdOut().writer();
    var gpa = std.heap.GeneralPurposeAllocator(.{}){};
    defer _ = gpa.deinit();
    const allocator = gpa.allocator();

    const config = try lerOuCriarConfig(allocator);
    defer allocator.free(config);

    try stdout.print("Configuração:\n{s}\n", .{config});
}

Veja Também

Continue aprendendo Zig

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