Directories

for Zig 0.15.2 Buy

Directories

Getting the current directory in Zig

This data type can be useful for different tasks. It’s good to know which directory we’re in at any given time and act accordingly.

get_current_dir.zig

const std = @import("std");

const print = std.debug.print;

pub fn main() void {

    // get data for the cwd (current working dir)

    const o_cwd = std.fs.cwd();

    // prepare a buffer to hold the response

    var a_buff: [std.fs.max_path_bytes]u8 = undefined;

    // get the real path of "." (current dir) and handle any error

    if (o_cwd.realpath(".", &a_buff)) |s_path| {

        print("Path {s}\n", .{s_path});

    } else |err_x| {

        print("Error {any}\n", .{err_x});

    }

}

$ zig run get_current_dir.zig

Path /home/zenofzig/code/9

We’re using an array as a buffer to store the response from the realpath function:

 // prepare a buffer to hold the response

 var a_buff: [std.fs.max_path_bytes]u8 = undefined;

The maximum length that a path name can use is defined in std.fs.max_path_bytes and depends on the platform.

As an alternative to the realpath function, we can use realpathAlloc, which requires a memory allocator.

get_current_dir_alloc.zig

const std = @import("std");

const print = std.debug.print;

pub fn main() !void {

    // get data for the cwd (current working dir)

    const o_cwd = std.fs.cwd();

    const o_alloc = std.heap.page_allocator;

    // get the real path of "." (current dir) and handle any error

    if (o_cwd.realpathAlloc(o_alloc, ".")) |s_path| {

        // free the memory of s_path

        // even though in this linear program

        // it would be freed at the end of main

        defer o_alloc.free(s_path);

        print("Path {s}\n", .{s_path});

    } else |err_x| {

        print("Error {any}\n", .{err_x});

    }

}

$ zig run get_current_dir_alloc.zig

Path /home/zenofzig/code/9

Check directory access

If we just want to know whether a directory exists and we have access to it, we could use something like this:

check_dir.zig

const std = @import("std");

const print = std.debug.print;

fn check_dir(s_dir: []const u8) !void {

    var o_dir = try std.fs.openDirAbsolute(

        s_dir,

        .{},

    );

    defer o_dir.close();

    try o_dir.access(".", .{});

}

pub fn main() void {

    const s_dir = "/root/";

    const s_msg = if (check_dir(s_dir))

        "Exists"

    else |err_x|

        @errorName(err_x);

    print("{s}\n", .{s_msg});

}

$ zig run check_dir.zig

AccessDenied

Iterate over a directory

        In the following example, we go through the entries of a directory and print them. We use the function std.fs.Dir.iterate or iterateAssumeFirstIteration. The latter is used when we know we haven’t iterated over the directory before. For example, if this is the first iteration, it’s because we just opened the directory.

The key point is that these functions return an iterator.

We use the iterator i_dir by calling its .next() method to move to the next entry in the directory, if one exists.

It’s a perfect case to list directory contents using our trusty while loop:

list_dir.zig

const std = @import("std");

const print = std.debug.print;

pub fn main() !void {

    const s_dir = "/";

    // open the directory

    var o_dir = std.fs.openDirAbsolute(

        s_dir,

        // flag needed to iterate over the dir

        .{ .iterate = true },

    ) catch |err_x| {

        // if it doesn't exist or another error occurs:

        print("Error: {s} \n", .{@errorName(err_x)});

        return;

    };

    // close the dir

    defer o_dir.close();

    // iterator to go through directory entries

    var i_dir = o_dir.iterateAssumeFirstIteration();

    // while there are entries, print them

    while (try i_dir.next()) |o_entry| {

        print("{s}\n", .{o_entry.name});

    }

}

$ zig run list_dir.zig

srv

dev

tmp

...

When we open the directory, to be able to create an iterator, we need to explicitly set the .iterate = true flag in the second argument.

You might be wondering: how do I know which flag to set to be able to iterate? And how can I find out other details about a function or object?

Earlier in the book, we saw how to do this with .empty:

https://zenofzig.com/libro/c7-listas-dinamicas-arraylist.html. To avoid repeating myself and keep it short: in all languages, it’s important to check the documentation and the source code.

If you look at the declaration of the openDirAbsolute function, you’ll see this:

fs.zig

 pub fn openDirAbsolute(

     absolute_path: []const u8, 

     flags: Dir.OpenOptions) File.OpenError!Dir {

 // ...

Notice those flags: Dir.OpenOptions

Dir.zig

 pub const OpenOptions = struct {

    /// ...

    /// `true` means the opened directory

    /// can be scanned for the files and sub-directories

    /// of the result. It means the `iterate` function can be called.

    iterate: bool = false,

    /// ...

};

This documentation explains that to iterate over the entries of a directory, you must set .iterate = true when opening it.

Also if you omit this flag, the program will crash with this message:

.BADF => unreachable, // Dir is invalid or was opened without iteration ability

All I can recommend is: check the functions you’re going to use and read their documentation, even just briefly. When working with files and directories, be careful: don’t accidentally delete or overwrite something important. Another tip: while you’re learning, do your tests in the /tmp/ directory.

Create and delete a directory

        WARNING: If you run code in the zenofzig.com playgrounds, there’s no risk of deleting anything important. But if you run code that deletes files or directories on your own machine (not in the browser), make sure you understand exactly what it does before running it. You could potentially delete something important, so be careful.

To create a new directory at an absolute path:

create_dir.zig

const std = @import("std");

const print = std.debug.print;

pub fn main() !void {

    // create a dir at an absolute path

    try std.fs.makeDirAbsolute("/tmp/newdir");

}

$ zig run create_dir.zig

...

To delete that same directory, use:

 // delete a dir

 try std.fs.deleteDirAbsolute("/tmp/newdir");


Files
Chapter summary
© 2025 - 2026 Zen of Zig