Ch11.13: POSIX File APIs

Overview

On every POSIX compliant system (Linux, FreeBSD, macOS, etc.), files are accessed through a small set of system calls: open, openat, read, write, close, and friends. These calls operate on a raw integer file descriptor (int).

fast_io wraps these system calls behind two types:

Opening a File with posix_file

The most common case: open a file by name and read/write with print and println.


#include <fast_io.h>
#include <fast_io_device.h>

int main()
{
    using namespace ::fast_io::iomnp;
    // Open a file for writing. The file is closed automatically
    // when `pf` goes out of scope.
    ::fast_io::posix_file pf(u8"hello_posix.txt", ::fast_io::open_mode::out);

    // fast_io's print/println work directly on posix_file.
    println(pf, u8"Hello from posix_file!");

    ::std::size_t const n{42zu};
    println(pf, u8"The answer is: ", n);
}
      

posix_file's constructor forwards to open with flags derived from ::fast_io::open_mode. The destructor calls close if the file descriptor is valid.

Wrapping an Existing File Descriptor

Sometimes you receive an int fd from legacy code, a library, or a system call you made directly. You can wrap it without duplicating or taking ownership:


#include <fast_io.h>
#include <fast_io_device.h>
#include <unistd.h>

int main()
{
    using namespace ::fast_io::iomnp;
    // A raw file descriptor from somewhere else in your program.
    int fd{::open("legacy.txt", O_WRONLY | O_CREAT | O_TRUNC, 0644)};

    // Non-owning observer: does NOT close the fd on destruction.
    ::fast_io::posix_io_observer observer{fd};
    println(observer, u8"Written through a posix_io_observer\n");

    // If you want ownership, construct a posix_file. It will close
    // the fd when it goes out of scope.
    ::fast_io::posix_file owned{::fast_io::from_fd, fd};
    println(owned, u8"Written through an owning posix_file\n");
}
      

Choose posix_io_observer when the file descriptor's lifetime is managed elsewhere. Choose posix_file when you want RAII cleanup.

Reading with posix_file

Input works through scan, which reads from the underlying file descriptor using read:


#include <fast_io.h>
#include <fast_io_device.h>

int main()
{
    using namespace ::fast_io::iomnp;
    ::fast_io::posix_file inpf(u8"input.txt", ::fast_io::open_mode::in);

    ::std::size_t value{};
    scan(inpf, value);

    ::fast_io::posix_file outpf(u8"output.txt", ::fast_io::open_mode::out);
    println(outpf, u8"Read the value: ", value);
}
      

Open-at Relative to a Directory

Just like obuf_file from earlier chapters, posix_file works with at(dir) to open files relative to a directory file descriptor, using openat under the hood:


#include <fast_io.h>
#include <fast_io_device.h>

int main(int argc, char** argv)
{
    using namespace ::fast_io::iomnp;
    ::fast_io::posix_file dir{::fast_io::mnp::os_c_str(argv[1]),
                              ::fast_io::open_mode::directory};
    ::fast_io::posix_file pf(at(dir), u8"relative.txt",
                             ::fast_io::open_mode::out);
    println(pf, u8"This file is opened with openat()\n");
}
      

Summary