c++怎么保证写入文件的同步性_flush与endl的性能对比【避坑】

千雪吖_8088

千雪吖_8088

2026-03-25

544人浏览

原创

std::ofstream默认带缓冲且不触发fsync,数据写入后未必立即落盘;需权衡性能与可靠性:定期fsync+安全close,或启用O_SYNC等同步标志。

c++怎么保证写入文件的同步性_flush与endl的性能对比【避坑】

写入文件后数据没立刻落盘,std::ofstream 默认不保证同步

默认情况下,C++ 的 std::ofstream 是带缓冲的,write() 或 操作只写到用户态缓冲区,不触发系统调用。哪怕程序正常退出,内核也可能延迟刷盘——断电或崩溃时就丢数据。

关键不是“要不要同步”,而是“在哪一层同步”:是冲刷 C++ 流缓冲(flush()),还是确保 OS 写入磁盘(fsync() 或 _commit())?

  • flush() 只把流缓冲交给 OS,不等磁盘确认;endl 等价于 ,纯属多一次无意义的 flush
  • Windows 下需额外调用 _commit(fd)(_fileno(os.rdbuf()->pubsync()) 获取 fd);Linux/macOS 用 fsync(fd)
  • 频繁调用 flush() 或 endl 会显著拖慢吞吐,尤其小块写入时——每写一行都 flush,性能可能跌 10 倍以上

endl 和 flush() 性能差在哪?看底层调用链

endl 不是“换行+同步”的原子操作,它只是先插入 '\n',再调用 basic_ostream::flush()。而 flush() 本身不发 fsync,只调用 streambuf::sync(),最终多数实现转为 write() 系统调用——但 OS 层仍走 page cache。

  • 写 10 万行,用 endl:约 10 万次 write() + 10 万次 flush() 调用开销
  • 同量数据,用 '\n' + 最后一次 flush():约 10 万次 write() + 1 次 flush()
  • 若还需落盘,必须手动加 fsync() 或 _commit(),endl 完全不帮你做这件事

真正需要同步时,绕过 iostream 直接控制 fd 更可靠

iostream 的抽象层在同步语义上太模糊:你无法控制是否 bypass buffer、是否等待磁盘完成、甚至不能跨平台统一行为。生产环境写关键日志或事务文件,建议退到 C 文件接口或 POSIX。

C++14
C++14

C++14 对 C++11 的修正与增强版本,适合旧系统维护和较老工具链兼容。

下载
  • Linux/macOS:int fd = open("log.txt", O_WRONLY | O_APPEND | O_SYNC); —— O_SYNC 让每次 write() 等待磁盘确认(性能差但语义明确)
  • Windows:HANDLE h = CreateFileA("log.txt", GENERIC_WRITE, 0, nullptr, OPEN_ALWAYS, FILE_FLAG_WRITE_THROUGH | FILE_FLAG_NO_BUFFERING, nullptr); —— 注意 NO_BUFFERING 要求对齐 I/O
  • 如果必须用 std::ofstream,至少禁用缓冲:os.rdbuf()->pubsetbuf(nullptr, 0);,再配合 os.flush() + _commit(_fileno(os.rdbuf()->pubsync()))

别信“std::ios_base::sync_with_stdio(false) 能解决同步问题”

这个开关只影响 C++ 流和 C stdio(printf/fputs)之间的锁竞争,跟数据是否落盘完全无关。关掉它可能让 cout 更快,但对 ofstream 的持久性零影响。

  • 它不改变缓冲策略(rdbuf()->pubsetbuf 才管这个)
  • 它不触发 fsync,也不影响 close() 行为
  • 误以为开了它就“安全”,反而更危险——因为关同步后,流和 C 函数混用可能引发未定义行为,但落盘问题依旧存在

同步这事没有银弹。要么接受默认缓冲的性能,靠定期 fsync + 异常安全 close 保底;要么用 O_SYNC 或 FILE_FLAG_WRITE_THROUGH 换取确定性,代价是吞吐。选哪个,得看你的数据丢了能不能接受。

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

相关文章

数码产品性能查询
数码产品性能查询

该软件包括了市面上所有手机CPU,手机跑分情况,电脑CPU,电脑产品信息等等,方便需要大家查阅数码产品最新情况,了解产品特性,能够进行对比选择最具性价比的商品。

下载

相关标签:

c++

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

相关专题

更多
Vite 项目如何打包和部署
Vite 项目如何打包和部署

Vite项目打包部署专题汇集生产构建、产物预览、输出目录、资源路径、Nginx与GitHub Pages部署及常见白屏和路由404问题的已审核文章,帮助读者完成上线流程。

2026.10.28

40

16

Vite 如何搭配 Vue.js
Vite 如何搭配 Vue.js

Vite搭配Vue.js专题汇集创建Vue 3项目、配置开发环境、路径别名、Vue插件、代理、多环境构建与调试的已审核文章,帮助读者完成从初始化到日常开发的配置。

2026.10.28

20

15

Vite 项目目录怎么看
Vite 项目目录怎么看

Vite项目目录专题汇集入口文件、src源码、public静态资源、路径别名、项目根目录和构建输出目录相关的已审核文章,帮助读者理解各文件夹的用途与引用方式。

2026.10.28

40

10

Gradle插件开发入门教程
Gradle插件开发入门教程

本专题介绍Gradle插件开发的基本流程,涵盖插件类编写、自定义任务注册、扩展参数设计和插件应用方法,帮助你理解插件如何组织构建逻辑,减少多个项目之间的重复配置。

2026.10.22

120

11

Gradle Wrapper配置教程
Gradle Wrapper配置教程

本专题介绍Gradle Wrapper的基本作用,涵盖文件组成、生成方法、版本配置和任务调用,帮助你理解项目如何使用指定的Gradle版本,减少不同开发环境带来的构建差异。

2026.10.22

80

10

Golangci-lint检查器使用教程
Golangci-lint检查器使用教程

本专题整理Golangci-lint常用Linters的用途与配置方法,覆盖错误处理、无效代码、安全、复杂度、命名和依赖检查,帮助项目合理选规则。

2026.10.22

80

15

Gradle怎么构建Java项目
Gradle怎么构建Java项目

本专题介绍Gradle Java项目构建方法,涵盖Java插件配置、依赖声明、源码编译、测试执行和打包检查,帮助你理解各阶段的任务关系,逐步完成项目构建。

2026.10.22

40

10

PHP时间戳漏洞修复教程
PHP时间戳漏洞修复教程

本专题汇总PHP常见时间戳漏洞,包括2038年溢出、时区漂移、时间戳伪造、重放攻击、时间盲注与日志审计失效等,并给出升级64位环境、使用 DateTimeImmutable、统一UTC、严格超时校验、预处理绑定、hash_equals 比对等修复方案,帮助开发者快速排查和加固时间相关代码。

2026.10.22

80

25

Golangci-lint配置文件与规则设置
Golangci-lint配置文件与规则设置

本专题聚焦Golangci-lint YAML配置文件,讲清运行参数、规则启停、目录排除、问题过滤及严重级别设置,便于团队统一检查标准。

2026.10.22

40

15

热门下载

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

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
C++ Core Guidelines
C++ Core Guidelines

共0课时 | 0人学习

C++ Reference
C++ Reference

共0课时 | 0人学习

C++ 官方标准说明
C++ 官方标准说明

共0课时 | 0人学习