Ch11.18: Filesystem APIs
Overview
::fast_io::dir_file opens a directory handle for enumeration. Combined
with at(), current(), and recursive(), it provides
a powerful, type-safe way to traverse the filesystem. Each iteration yields a
directory_entry with functions to query the filename, extension, and file type.
Opening a Directory
Construct a dir_file from a path. The constructor accepts anything convertible
to a C string — C strings, string_view, u8string, or wrapped
with os_c_str.
#include <fast_io.h>
#include <fast_io_device.h>
int main(int argc, char** argv) {
using namespace ::fast_io::iomnp;
// From a string literal (no wrapping needed)
::fast_io::dir_file df(u8"/home/user/docs");
// From a runtime C string (must wrap with os_c_str)
::fast_io::dir_file df2(::fast_io::mnp::os_c_str(argv[1]));
}
The at() Function
Call at(df) to get an at_entry — a lightweight handle anchored
at the directory. This handle is used by current() and recursive() to
enumerate entries, and can also be used to open files relative to the directory (as shown in
Ch11.1).
::fast_io::dir_file df(u8"my_directory");
auto entry = at(df); // at_entry anchored at my_directory
Iterating Immediate Children: current()
current(at(df)) returns a range that yields each immediate child of the directory
(non-recursive). Use it in a range-for loop:
#include <fast_io.h>
#include <fast_io_device.h>
int main() {
using namespace ::fast_io::iomnp;
::fast_io::dir_file df(u8".");
for (auto const& ent : current(at(df)))
{
if (is_dot(ent)) continue; // skip . and ..
switch (type(ent)) {
using enum ::fast_io::file_type;
case directory: print("[DIR] "); break;
case symlink: print("[LINK] "); break;
case regular: print("[FILE] "); break;
default: print("[OTHER]");
}
println(::fast_io::mnp::code_cvt(u8filename(ent)));
}
}
Recursive Traversal: recursive()
recursive(at(df)) walks all descendants of the directory, yielding every file
and subdirectory it contains. This is ideal for searching or processing entire directory trees.
#include <fast_io.h>
#include <fast_io_device.h>
int main() {
using namespace ::fast_io::iomnp;
::fast_io::dir_file df(u8"src");
::std::size_t cpp_count{};
::std::size_t total_lines{};
for (auto const& ent : recursive(at(df)))
{
if (type(ent) != ::fast_io::file_type::regular) continue;
::std::u8string_view ext{u8extension(ent)};
if (ext == u8".cpp" || ext == u8".h")
{
++cpp_count;
// Load the file and count lines
::fast_io::native_file_loader loader(drt(ent));
for (auto ch : loader)
{
if (ch == u8'\n') ++total_lines;
}
}
}
println("Found ", cpp_count, " C++ files with ", total_lines, " total lines");
}
Directory Entry Functions
Each directory_entry yielded by current() or recursive()
exposes these functions:
| Function | Returns | Description |
|---|---|---|
u8filename(ent) |
char8_t string_view |
Filename in UTF-8. |
u8extension(ent) |
char8_t string_view |
Extension (from last . onward) in UTF-8. |
u8stem(ent) |
char8_t string_view |
Filename without extension in UTF-8. |
type(ent) |
file_type |
File type (see below). |
is_dot(ent) |
bool |
True if the name is . or ... |
drt(ent) |
fs_dirent |
A (fd, name) pair — pass to file constructors or loaders to open the entry. |
at(ent) |
at_entry |
Anchor *at-style operations relative to this entry. |
There are also native_filename(), native_extension(), and
native_stem() variants that return the filename in the native encoding
(which may not be UTF-8 on all platforms).
The file_type Enum
::fast_io::file_type categorizes filesystem entries:
| Value | Description |
|---|---|
regular | Regular file. |
directory | Directory. |
symlink | Symbolic link. |
block | Block device. |
character | Character device. |
fifo | FIFO (named pipe). |
socket | Socket. |
unknown | Unknown type. |
not_found | File does not exist. |
Opening Files Relative to Directory Entries
Use drt(ent) to get a (fd, name) pair that file constructors and loaders can
open directly. This is more efficient than building a full path, and avoids race conditions
from path resolution.
#include <fast_io.h>
#include <fast_io_device.h>
int main() {
using namespace ::fast_io::iomnp;
::fast_io::dir_file df(u8"data");
for (auto const& ent : current(at(df)))
{
if (type(ent) != ::fast_io::file_type::regular) continue;
// Open the entry directly using drt(ent)
::fast_io::native_file_loader loader(drt(ent));
println(::fast_io::mnp::code_cvt(u8filename(ent)), ": ", loader.size(), " bytes");
}
}
Key Takeaways
- Use
::fast_io::dir_fileto open a directory handle. - Call
at(df)to get anat_entryfor enumeration. - Use
current(at(df))for immediate children (non-recursive). - Use
recursive(at(df))to walk all descendants. - Each entry exposes
u8filename(),u8extension(),type(),is_dot(),drt(), andat(). - Use
drt(ent)to open files relative to directory entries efficiently. - Use
type(ent)with thefile_typeenum to filter by file type.