c++怎么防止程序意外退出导致的文件写入缓冲区丢失问题【实战】

夜雪小哥_3021

夜雪小哥_3021

2026-04-07

785人浏览

原创

强制刷盘需分层同步:先flush()清c++缓冲区,再pubsync()同步至file*,最后fsync()/flushfilebuffers()确保落盘;o_sync/o_dsync打开文件更可靠,但性能下降;析构函数不可靠,须手动同步。

c++怎么防止程序意外退出导致的文件写入缓冲区丢失问题【实战】

用 std::ofstream::flush() 强制刷盘,但别只靠它

单纯调用 flush() 并不能保证数据真正落盘——它只把 C++ 流缓冲区内容推到 C 标准库(FILE*)的缓冲区,操作系统和磁盘控制器仍有自己的缓存层级。尤其在程序被 SIGKILL、断电或崩溃时,flush() 后的数据仍可能丢失。

实战中必须分层处理:

  • 先调用 os.flush() 清空 C++ 流缓冲区
  • 再用 fflush(os.rdbuf()->pubsync()) 或更稳妥的 os.rdbuf()->pubsync()(返回值为 -1 表示失败)同步到底层 FILE*
  • 最后调用 fsync()(Linux/macOS)或 FlushFileBuffers()(Windows)确保内核缓冲区写入物理设备

例如:

std::ofstream os("data.bin", std::ios::binary);
os.write(buf, size);
if (!os || os.flush() == std::ostream::failbit) {
    // 处理流错误
}
// 同步 FILE*
if (os.rdbuf()->pubsync() == -1) {
    // 处理底层 sync 失败
}
// Linux/macOS:获取 fd 并 fsync
int fd = fileno(static_cast<:filebuf>(os.rdbuf())->fd());
fsync(fd);
</:filebuf>

用 O_SYNC 或 O_DSYNC 标志打开文件(POSIX 系统)

在构造 std::ofstream 前,用系统调用直接打开带同步语义的文件描述符,再绑定到流,能绕过部分用户态缓冲。这是比事后 fsync() 更彻底的方案,代价是写入性能明显下降。

关键点:

  • O_SYNC:每次 write() 都等待数据和元数据(如 mtime)落盘
  • O_DSYNC:只等数据落盘,不等元数据,性能稍好,适合日志类场景
  • C++ 标准流不直接支持这些 flag,需用 fdopen() 中转:int fd = open("log.txt", O_WRONLY | O_CREAT | O_SYNC, 0644); std::ofstream os(fdopen(fd, "w"));
  • 注意:fdopen() 后不要 close(fd),否则流失效;析构时 std::ofstream 会自动 fclose(),进而关闭 fd

避免依赖析构函数自动 flush —— 它救不了崩溃

std::ofstream 析构时会调用 close(),而 close() 在 POSIX 上**不保证**同步数据(除非文件以 O_SYNC 打开)。程序因段错误、std::abort() 或信号终止时,析构函数根本不会执行。

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

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

下载

所以:

  • 不要把关键数据写入逻辑放在类成员流中,指望“对象销毁就安全”
  • 对重要文件,写完立即手动同步,而不是等到作用域结束
  • 若必须用 RAII,自己封装一个类,在关键路径显式调用 commit() 方法,内部做 flush() + fsync()

例如临时文件写入后重命名的典型模式:

std::ofstream tmp("data.tmp", std::ios::binary);
tmp.write(...);
tmp.flush();
fsync(fileno(tmp.rdbuf()->fd())); // 确保 tmp 写完
tmp.close();
rename("data.tmp", "data.bin"); // 原子替换

Windows 下必须用 FlushFileBuffers(),fflush() 不够

Windows 的 CRT 缓冲行为与 POSIX 不同:fflush() 只清到 CRT 层,不触发系统级写入。即使开了 _IONBF,也不能替代 FlushFileBuffers()。

实操要点:

  • 从 std::ofstream 获取 HANDLE:先用 _get_osfhandle(_fileno(os.fileno()))(注意 os.fileno() 是非标准扩展,MSVC 支持,GCC/Clang 不行;更兼容的做法是用 CreateFile() + fdopen()
  • 调用前检查句柄有效性:if (h != INVALID_HANDLE_VALUE) FlushFileBuffers(h);
  • 若使用 std::fstream 且需跨平台,建议抽象出 sync_to_disk(int fd) 函数,内部按 OS 分支调用 fsync() 或 FlushFileBuffers()

容易忽略的一点:NTFS 默认启用“延迟写入”,即使调用了 FlushFileBuffers(),若磁盘固件或 RAID 卡有写缓存,仍可能丢数据——生产环境需确认存储设备已禁用写缓存(hdparm -W0 /dev/sdX 或厂商工具)。

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

相关文章

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

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

下载

相关标签:

c++

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

相关专题

更多
fclose函数的用法
fclose函数的用法

fclose是一个C语言和C++中的标准库函数,用于关闭一个已经打开的文件,是文件操作中非常重要的一个函数,用于将文件流与底层文件系统分离,释放相关的资源。更多关于fclose函数的相关问题,详情请看本专题下面的文章。php中文网欢迎大家前来学习。

2023.11.30

822

9

string转int
string转int

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

2023.08.02

5659

3

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

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

2024.08.29

2825

6

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

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

2025.08.29

3528

10

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

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

2025.08.29

2505

10

windows查看端口占用情况
windows查看端口占用情况

Windows端口可以认为是计算机与外界通讯交流的出入口。逻辑意义上的端口一般是指TCP/IP协议中的端口,端口号的范围从0到65535,比如用于浏览网页服务的80端口,用于FTP服务的21端口等等。怎么查看windows端口占用情况呢?php中文网给大家带来了相关的教程以及文章,欢迎大家前来阅读学习。

2023.07.26

3099

3

查看端口占用情况windows
查看端口占用情况windows

端口占用是指与端口关联的软件占用端口而使得其他应用程序无法使用这些端口,端口占用问题是计算机系统编程领域的一个常见问题,端口占用的根本原因可能是操作系统的一些错误,服务器也可能会出现端口占用问题。php中文网给大家带来了相关的教程以及文章,欢迎大家前来学习阅读。

2023.07.27

2658

6

windows照片无法显示
windows照片无法显示

当我们尝试打开一张图片时,可能会出现一个错误提示,提示说"Windows照片查看器无法显示此图片,因为计算机上的可用内存不足",本专题为大家提供windows照片无法显示相关的文章,帮助大家解决该问题。

2023.08.01

1448

3

windows查看端口被占用的情况
windows查看端口被占用的情况

windows查看端口被占用的情况的方法:1、使用Windows自带的资源监视器;2、使用命令提示符查看端口信息;3、使用任务管理器查看占用端口的进程。本专题为大家提供windows查看端口被占用的情况的相关的文章、下载、课程内容,供大家免费下载体验。

2023.08.02

2439

5

热门下载

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

精品课程

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

共0课时 | 0人学习

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

共0课时 | 0人学习

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

共0课时 | 0人学习