List and Filter Files in a Directory in Zig
List top-level files and return results matching a filter, no recursion.
This recipe was written using Zig version
0.15.2. If this recipe is outdated, please let me know on X (@sepyke) or Bluesky (@pyk.sh).
Recently, I was building a simple library and needed to list all Zig files in an
examples directory to build them as binaries in my build.zig. This recipe
shows how to use std.fs.Dir.iterate() to list files in a single directory and
filter them.
Similar to Dir.walk(), you first need a directory handle. You can get this by
using std.fs.cwd() for the current working directory and then openDir() to
access your target subdirectory (e.g. “examples”). Just like with walk(), it’s
important to ensure .iterate = true is set in OpenOptions when opening the
directory to allow its contents to be read.
The Dir.iterate() function returns an Iterator that goes through the
immediate contents of a directory. It does not traverse into subdirectories,
making it a more direct and efficient option when you only need top-level files.
Here is the code snippet with the inline comments:
const std = @import("std");
const fs = std.fs;
const mem = std.mem;
const Allocator = mem.Allocator;
pub fn main() !void {
// In a real `build.zig`, `fs.cwd()` would typically be your project root.
// For this demonstration, we'll use a temporary directory to keep things clean.
var tmp = std.testing.tmpDir(.{});
defer tmp.cleanup(); // Clean up the temporary directory when done.
const base_dir = tmp.dir;
// Create the 'examples' directory and some files inside it for testing.
try base_dir.makeDir("examples");
try base_dir.writeFile(.{ .sub_path = "examples/main.zig", .data = "const a = 1;" });
try base_dir.makePath("examples/utils"); // Create a subdirectory
try base_dir.writeFile(.{ .sub_path = "examples/utils/helper.zig", .data = "const b = 2;" }); // This one won't be found by `iterate()`
try base_dir.writeFile(.{ .sub_path = "examples/README.md", .data = "docs" }); // A non-Zig file
const sub_dir_to_scan = "examples";
std.debug.print("Searching for .zig files non-recursively in subdirectory: '{s}'\n", .{sub_dir_to_scan});
// Open the target subdirectory with iteration enabled.
var target_dir = try base_dir.openDir(sub_dir_to_scan, .{
.iterate = true,
});
defer target_dir.close(); // Always remember to close directory handles!
std.debug.print("Found files:\n", .{});
var iter = target_dir.iterate();
while (try iter.next()) |entry| {
// We only care about files that end with ".zig".
// `entry.kind == .file` checks if it's a file, not a directory.
if (entry.kind == .file and mem.endsWith(u8, entry.name, ".zig")) {
std.debug.print("file: {s}\n", .{entry.name});
}
}
}Make sure the zig is intalled:
$ zig version
0.15.2Then run it:
$ zig run list_files_in_directory.zig
Searching for .zig files non-recursively in subdirectory: 'examples'
Found files:
file: main.zig