块式读写器(block_read_writer)
block_read_writer<T>
为“块式 I/O”提供一个轻量的用户态缓冲与读写指针管理器。
它在调用方与底层原始 I/O 对象(如 file
)之间维护一段活动缓冲区与独立的读/写位置,
使顺序与随机读写更易用,同时保留“无用户态缓冲的原始 I/O”的可控性:
未 flush()
前的数据仅对当前对象可见,flush()
后才落到下层 I/O。
要点
- 读写统一接口:顺序/随机读写、独立
seekg/seekp
与tellg/tellp
- 显式持久化:
flush()
前写入仅缓存在内存,flush()
后写入到底层 I/O - 读可见性:未
flush()
的写入,对同一block_read_writer
的后续读取是可见的 - 析构自动刷写:对象析构时会调用
flush()
,尝试将缓冲写入到底层 I/O - 协程语义:
read()
可被打断;write()
与flush()
不可打断 - 模板约束:
T
需满足block_read_write
概念(例如asco::io::file
)
快速上手
using asco::io::file;
using asco::io::buffer;
using asco::io::seekpos;
using asco::block_read_writer;
auto r = co_await file::at("/tmp/demo.bin")
.read()
.write()
.create()
.truncate()
.mode(0644)
.open();
if (!r) co_return;
block_read_writer<file> brw(std::move(*r));
// 写入两段数据(此时仅缓存在 brw 中)
co_await brw.write(buffer("Hello"));
co_await brw.write(buffer("World"));
assert(brw.tellp() == 10);
// 读取(未 flush 的写入对同一 brw 可见)
brw.seekg(0, seekpos::begin);
auto b = co_await brw.read(1024);
std::string s = b ? std::move(*b).to_string() : "";
// 显式持久化到底层 I/O (推荐在作用域结束前显式调用)
co_await brw.flush();
API 概览
模板
template<block_read_write T> class block_read_writer;
- 示例:
block_read_writer<asco::io::file>
- 示例:
构造/析构
block_read_writer(T&& ioo)
block_read_writer(const T& ioo)
~block_read_writer()
:析构时调用flush()
尝试刷写缓冲
读写与缓冲
future<std::optional<buffer<>>> read(size_t nbytes)
- 成功时返回数据;到达 EOF 返回
std::nullopt
- 可被打断
- 成功时返回数据;到达 EOF 返回
future<void> write(buffer<> buf)
- 仅更新内部活动缓冲区与写指针;不可打断
future<void> flush()
- 将内部活动缓冲区自
buffer_start
起写入到底层 I/O;不可打断
- 将内部活动缓冲区自
定位与查询
size_t seekg(ssize_t offset, seekpos whence = seekpos::current)
size_t seekp(ssize_t offset, seekpos whence = seekpos::current)
size_t tellg() const noexcept
size_t tellp() const noexcept
行为与语义
- 写入可见性
- 未
flush()
的写入对同一block_read_writer
的后续read()
可见 - 调用
flush()
后方才写入到底层 I/O 对象
- 未
- 读写指针
tellg/tellp
分别为读取进度与写入进度seekg/seekp
相互独立,互不影响
- 打断语义
read()
支持在等待过程中被打断;write()
与flush()
不支持打断
- 析构行为
- 析构函数会调用
flush()
刷写缓冲。
- 析构函数会调用
示例:覆盖写与稀疏写
// 初始内容
co_await brw.write(buffer("HelloWorld"));
co_await brw.flush();
// 覆盖中间 4 字节为 "ASCO"(总长度不变)
brw.seekp(6, seekpos::begin);
co_await brw.write(buffer("ASCO"));
// 形成 10 字节洞并在其后写 'X'
brw.seekp(20, seekpos::begin);
co_await brw.write(buffer("X"));
// 未 flush 时,通过 brw 读取可见:
brw.seekg(0, seekpos::begin);
std::string all;
while (auto part = co_await brw.read(4096)) all += std::move(*part).to_string();
co_await brw.flush(); // 持久化到底层
依赖与概念
- 需包含:
<asco/io/bufio.h>
、<asco/io/buffer.h>
T
必须满足block_read_write
概念(如asco::io::file
)
注意事项
- 非线程安全
- 在
flush()
前,其他对象(或进程)无法从底层 I/O 中看到你的写入