c++怎么在读写文件时触发回调函数_观察者模式与流封装【进阶】

云丽酱_4389

云丽酱_4389

2026-03-28

732人浏览

原创

std::fstream 本身不支持回调,需继承 std::streambuf 并重写 underflow()、sputn() 等函数实现底层字节级拦截;回调应置于 overflow()/sputn() 或 underflow()/sgetn() 中,避免在非虚函数或 sync() 中误用,注意跨平台差异与线程安全。

c++怎么在读写文件时触发回调函数_观察者模式与流封装【进阶】

std::fstream 本身不支持回调,得自己封装流缓冲区

标准 C++ 的 std::ifstream 和 std::ofstream 是被动的——你调它,它读写;它不会主动通知你“我刚读了 1024 字节”或“写入失败了”。想加回调,必须绕过高层流接口,接管底层的 std::streambuf。这不是加个 lambda 就能搞定的事,而是要继承 std::streambuf,重写 underflow()、overflow()、sputn() 等关键函数。

常见错误是试图在 operator>> 或 read() 后手动插回调——这只能捕获“调用时机”,无法感知底层实际传输字节、缓冲区刷新、甚至系统 write() 返回值。真正需要回调的场景(比如实时日志上传、加密流处理、进度上报),必须在缓冲区粒度上拦截。

  • 别碰 std::iostream::rdbuf() 返回的原生 streambuf*,它是只读视图;要 new 一个自定义子类实例,再用 rdbuf() 替换
  • 重写 overflow(int c) 处理单字符写入,sputn(const char* s, std::streamsize n) 处理批量写入——后者才是性能关键路径
  • 读操作同理:underflow() 触发填充输入缓冲区时回调,sgetn() 对应批量读取
  • 记得在自定义 streambuf 析构时,把原始 streambuf*(如文件对应的 filebuf)正确 delete 或移交所有权,否则资源泄漏

回调触发点选哪个函数,取决于你要观察什么

不是所有缓冲区函数都适合塞回调。选错会导致重复触发、漏触发,或者破坏流语义。

C++ Code Review Master
C++ Code Review Master

组合式C++代码评审方案,融合静态分析、AI推理、多轮迭代评审和C++专项检查,适用于PR审查、增量代码审查、全项目评审和代码质量评分,触发词包括review cpp、cpp代码评审、C++review、代码审查。

下载
  • 想监控“每次系统级 write 调用”:在 sync() 里触发回调——它对应 flush() 或缓冲区满时的底层同步,但注意:sync() 不一定每次 write() 都调,且可能被忽略(比如 std::ios_base::out | std::ios_base::app 模式下行为不同)
  • 想精确知道“哪几个字节被送进系统调用”:必须在 overflow() 和 sputn() 内部,在调用父类原始写逻辑前后插回调——例如先调 callback("write", s, n),再调 original_sputn(s, n)
  • 读场景同理:underflow() 适合通知“新一批数据已从磁盘加载进缓冲区”,而 sgetn() 更适合通知“用户代码实际取走了多少字节”
  • 避免在 xsgetn() / xsputn() 这类非虚函数里动手——它们不是标准重写点,各编译器实现可能跳过

观察者模式怎么和 streambuf 安全绑定

不能让 streambuf 直接持有 std::function 并无条件调用——回调里如果又去操作同一个流(比如在写回调里调 flush()),极易引发递归重入或迭代器失效。

  • 用弱引用管理观察者:存储 std::weak_ptr<observer></observer>,每次触发前 lock() 判断是否还存活,避免悬挂调用
  • 回调函数签名建议固定为 void(std::string_view event, const void* data, size_t size, std::error_code ec),统一覆盖读/写/错误三类事件,比拆成多个回调更易维护
  • 不要在回调里做耗时操作(如网络请求、磁盘写入)——streambuf 是同步阻塞路径,卡住会影响整个流行为;真要异步,回调内只发消息到队列,另起线程处理
  • 注意多线程:同一个 streambuf 实例被多个线程共用时(比如共享的 std::ostream&),回调触发点必须加锁;更稳妥的做法是每个线程独占一个带回调的流实例

Windows 下 filebuf 的 sync() 行为和 Linux 不一致

这是容易被忽略的坑。在 Windows 上,std::filebuf::sync() 默认会调用 _commit()(即 FlushFileBuffers),强制落盘;Linux 下则只是 fflush(),不保证物理写入。如果你的回调依赖 sync() 触发来表示“数据已持久化”,那跨平台时逻辑就错了。

  • 别假设 sync() = “已落盘”;真正需要落盘语义,应在回调里显式调用 fsync()(Linux)或 FlushFileBuffers()(Windows),并检查返回值
  • 用 std::ofstream 构造时传 std::ios_base::unitbuf 可让每次插入符后自动 flush(),但它不改变 sync() 底层行为,只是增加调用频次
  • 测试时务必在目标平台实测:用 Process Monitor(Windows)或 strace -e trace=write,fsync,fcntl(Linux)验证回调触发时刻与系统调用是否对齐

流缓冲区回调不是语法糖,是侵入式改造。最复杂的点不在怎么写,而在怎么收口——回调里能不能抛异常?析构时要不要等回调完成?这些边界没想清,上线后只会变成偶发崩溃或静默丢数据。

C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!

相关文章

c++速学教程(入门到精通)
c++速学教程(入门到精通)

c++怎么学习?c++怎么入门?c++在哪学?c++怎么学才快?不用担心,这里为大家提供了c++速学教程(入门到精通),有需要的小伙伴保存下载就能学习啦!

下载

相关标签:

c++

本站声明:本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn

相关专题

更多
c语言const用法
c语言const用法

const是关键字,可以用于声明常量、函数参数中的const修饰符、const修饰函数返回值、const修饰指针。详细介绍:1、声明常量,const关键字可用于声明常量,常量的值在程序运行期间不可修改,常量可以是基本数据类型,如整数、浮点数、字符等,也可是自定义的数据类型;2、函数参数中的const修饰符,const关键字可用于函数的参数中,表示该参数在函数内部不可修改等等。

2023.09.20

2078

7

string转int
string转int

在编程中,我们经常会遇到需要将字符串(str)转换为整数(int)的情况。这可能是因为我们需要对字符串进行数值计算,或者需要将用户输入的字符串转换为整数进行处理。php中文网给大家带来了相关的教程以及文章,欢迎大家前来学习阅读。

2023.08.02

5839

3

int占多少字节
int占多少字节

int占4个字节,意味着一个int变量可以存储范围在-2,147,483,648到2,147,483,647之间的整数值,在某些情况下也可能是2个字节或8个字节,int是一种常用的数据类型,用于表示整数,需要根据具体情况选择合适的数据类型,以确保程序的正确性和性能。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

2024.08.29

2885

6

c++怎么把double转成int
c++怎么把double转成int

本专题整合了 c++ double相关教程,阅读专题下面的文章了解更多详细内容。

2025.08.29

3648

10

C++中int的含义
C++中int的含义

本专题整合了C++中int相关内容,阅读专题下面的文章了解更多详细内容。

2025.08.29

2565

10

javascriptvoid(o)怎么解决
javascriptvoid(o)怎么解决

javascriptvoid(o)的解决办法:1、检查语法错误;2、确保正确的执行环境;3、检查其他代码的冲突;4、使用事件委托;5、使用其他绑定方式;6、检查外部资源等等。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

2023.11.23

636

5

java中void的含义
java中void的含义

本专题整合了Java中void的相关内容,阅读专题下面的文章了解更多详细内容。

2025.11.27

351

13

lambda表达式
lambda表达式

Lambda表达式是一种匿名函数的简洁表示方式,它可以在需要函数作为参数的地方使用,并提供了一种更简洁、更灵活的编码方式,其语法为“lambda 参数列表: 表达式”,参数列表是函数的参数,可以包含一个或多个参数,用逗号分隔,表达式是函数的执行体,用于定义函数的具体操作。本专题为大家提供lambda表达式相关的文章、下载、课程内容,供大家免费下载体验。

2023.09.15

931

5

python lambda函数
python lambda函数

本专题整合了python lambda函数用法详解,阅读专题下面的文章了解更多详细内容。

2025.11.08

325

7

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
Conan 2 Essentials 免费课程
Conan 2 Essentials 免费课程

共0课时 | 0人学习

CMake 与 Conan 集成实践
CMake 与 Conan 集成实践

共0课时 | 0人学习

Conan 2 高级依赖模型介绍
Conan 2 高级依赖模型介绍

共0课时 | 0人学习