File I/O
Corosio provides two classes for asynchronous file operations:
stream_file for sequential access and random_access_file for
offset-based access. Both dispatch I/O to a worker thread on POSIX
platforms and use native overlapped I/O on Windows.
|
Code snippets assume:
|
Stream File
stream_file reads and writes sequentially, maintaining an internal
position that advances after each operation. It inherits from io_stream,
so it works with any algorithm that accepts an io_stream&.
Reading a File
corosio::stream_file f(ioc);
f.open("data.bin", corosio::file_base::read_only);
char buf[4096];
auto [ec, n] = co_await f.read_some(
capy::mutable_buffer(buf, sizeof(buf)));
if (ec == capy::cond::eof)
// reached end of file
Random Access File
random_access_file reads and writes at explicit byte offsets
without maintaining an internal position. This is useful for
databases, indices, or any workload that accesses non-sequential
regions of a file.
Open Flags
Both file types accept a bitmask of file_base::flags when opening:
| Flag | Meaning |
|---|---|
|
Open for reading (default) |
|
Open for writing |
|
Open for both reading and writing |
|
Create the file if it does not exist |
|
Fail if the file already exists (requires |
|
Truncate the file to zero length on open |
|
Seek to end on open (stream_file only) |
|
Synchronize data to disk on each write |
Flags are combined with |:
f.open("log.txt",
corosio::file_base::write_only
| corosio::file_base::create
| corosio::file_base::append);
File Metadata
Both file types provide synchronous metadata operations:
auto bytes = f.size(); // file size in bytes
f.resize(1024); // truncate or extend
f.sync_data(); // flush data to stable storage
f.sync_all(); // flush data and metadata
stream_file additionally provides seek() for repositioning.
Native Handle Access
Both file types support adopting and releasing native handles:
// Release ownership — caller must close the handle
auto handle = f.release();
assert(!f.is_open());
// Adopt an existing handle — file takes ownership
corosio::random_access_file f2(ioc);
f2.assign(handle);
Error Handling
File operations follow the same error model as sockets. Reads past
end-of-file return capy::cond::eof:
auto [ec, n] = co_await f.read_some(buf);
if (ec == capy::cond::eof)
{
// no more data
}
else if (ec)
{
// I/O error
}
Opening a nonexistent file with read_only throws std::system_error.
Use create to create files that may not exist.
Thread Safety
-
Distinct objects are safe to use concurrently.
-
random_access_filesupports multiple concurrent reads and writes from coroutines sharing the same file object. Each operation is independently heap-allocated. -
stream_fileallows at most one asynchronous operation in flight at a time (same as Asio’s stream_file). Sequential access with an implicit position makes concurrent ops semantically undefined. -
Non-async operations (open, close, size, resize, etc.) require external synchronization.