写入后必须检查 fail() 和 bad(),不能只看 good();fail() 表示写入失败或格式错误,bad() 表示流内部损坏(如物理介质故障),good() 过于宽泛易漏判,close() 必须显式调用并检查状态。

写入后必须检查 fail() 和 bad(),不能只看 good()
很多人以为写完 ofstream 就万事大吉,其实磁盘满、U 盘拔出、权限丢失这些物理层错误,operator 或 <code>write() 调用本身几乎不报错——它只是把数据塞进缓冲区,真正失败发生在缓冲区刷新或流析构时。所以你得在关键节点主动查状态。
常见错误现象:ofstream 构造成功、写操作没抛异常、文件看起来“生成了”,但实际内容为空或截断;或者程序退出后才发现文件大小为 0。
-
fail():表示格式错误或写入失败(含底层 I/O 错误),最常用 -
bad():表示流内部状态损坏(如缓冲区分配失败、底层 write() 返回 -1 且errno非EINTR),更严重,也更贴近物理介质崩坏 -
good()是四者合取,太宽泛,容易漏判;eof()在写入场景完全无关
关闭流前务必调用 close() 并检查返回值
构造函数或 open() 成功 ≠ 文件句柄真正可用;同理,ofstream 析构时自动 close() 会吞掉错误——你无法捕获它。显式调用 close() 才能拿到失败信号。
使用场景:日志落盘、配置保存、临时文件生成等对数据持久性有要求的操作。
-
ofstream::close()返回void,但它会设置流状态位,之后立刻查fail()或bad() - Linux 下若磁盘满,
close()可能触发ENOSPC,反映为badbit置位 - Windows 下拔掉 USB 设备后继续写,
close()常触发badbit(而非failbit)
std::ofstream f("data.bin", std::ios::binary);
f.write(buf, size);
if (!f) { /* 写入已失败 */ }
f.close();
if (f.bad()) { /* close 期间出问题,极可能是物理介质故障 */ }
sync_with_stdio(false) 会掩盖写入错误,生产环境慎用
禁用 C stdio 同步(std::ios::sync_with_stdio(false))能提升性能,但它会让 ofstream 的缓冲策略更激进,部分错误延迟暴露,甚至绕过内核 write() 的 errno 检查路径。
组合式C++代码评审方案,融合静态分析、AI推理、多轮迭代评审和C++专项检查,适用于PR审查、增量代码审查、全项目评审和代码质量评分,触发词包括review cpp、cpp代码评审、C++review、代码审查。
性能 / 兼容性影响:在嵌入式或低配设备上,该优化可能让磁盘满错误晚几秒才浮现,导致多条记录“看似成功”实则全丢。
- 调试阶段务必关掉它,确保错误第一时间可见
- 若必须开启,请在每次关键写入后加
f.flush(),并检查f.fail() - 不要依赖
std::cerr输出来判断——它和ofstream是独立流,cerr正常不代表文件流正常
跨平台检测物理错误要结合 errno 和流状态
C++ 标准流不直接暴露 errno,但底层失败通常会影响它。尤其当 bad() 为真时,errno 往往保留最后一次系统调用的错误码,这是定位物理原因的关键线索。
参数差异:Linux 下常见 ENOSPC(磁盘满)、EIO(I/O 错误)、EROFS(只读文件系统);Windows 下对应 ERROR_DISK_FULL、ERROR_WRITE_PROTECT 等,需用 GetLastError(),但流对象本身不提供接口,只能靠 bad() + 日志上下文推测。
- Linux 示例:检查
f.bad() && errno == ENOSPC可确认磁盘满 - 别在
catch(...)里查errno——流操作不抛异常(除非你手动开了exceptions()) - 如果启用了
f.exceptions(std::ios::failbit | std::ios::badbit),那errno可能在异常处理中已失效,优先信流状态
物理介质错误不是“会不会发生”的问题,而是“什么时候暴露”的问题。最危险的情况是:你以为写成功了,其实数据卡在缓冲区没刷下去,而进程刚好在此时崩溃或被 kill —— 这时候连 close() 都没机会执行。所以关键动作就三个:写后查 fail()、关流前显式 close() 并查 bad()、出错时顺手记下 errno。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!








