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:
-
::fast_io::posix_file— an RAII owning wrapper. It opens the file viaopen(oropenat) and guaranteescloseis called when the object goes out of scope. -
::fast_io::posix_io_observer— a non-owning view over an existing file descriptor. It is trivially copyable, has no destructor, and is safe to pass around by value.
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
-
::fast_io::posix_fileis an RAII wrapper around POSIXopen/close. -
::fast_io::posix_io_observeris a lightweight, non-owning view over an existing file descriptor. -
Both types plug directly into
::fast_io::print,::fast_io::println, and::fast_io::scan. -
You can wrap any raw
int fdwithout changing the rest of your code.