磁盘满时std::ofstream不立即设failbit/badbit,需在写失败后紧邻检查errno是否为ENOSPC(Linux/macOS)或_doserrno映射值(Windows),good()等状态检查无法预测磁盘满。
检查
和
不足以判断磁盘满
磁盘写满时,C++ 标准库的
通常不会立即设置
或
—— 它可能先缓存数据,直到
或析构时才真正尝试落盘。此时才可能触发失败,但错误已被“延迟暴露”。更关键的是:
可能由格式错误、权限不足、路径不存在等多种原因引起;
多指向底层流缓冲区崩溃(如
系统调用返回
),而磁盘满实际常返回
,它往往被封装在
中,标准流对象并不直接暴露它。
必须结合
和系统级检查才能可靠识别
当
写入失败(例如
为真或
返回
)后,应立刻检查
值是否为
。但注意:不同平台对
的保留行为不一致,需在失败后**紧邻地**读取,且不能有其他可能修改
的系统调用穿插。
的
会重置状态位,但**不会清空
**;而
或析构可能触发二次写入,覆盖
Linux/macOS 下可直接用
和
;Windows 需用
并映射(
或
)
示例逻辑:
避免依赖
或
做提前预判
是
的组合,它只反映流对象自身的状态,完全无法预测下一次写是否成功——尤其对磁盘满这种外部资源限制,流对象无感知。试图用
推算剩余空间更是危险:文件系统预留空间、配额、稀疏文件、快照机制都会让结果失真。
不要写
不要用
/
检查剩余空间再写,因为两次调用之间可能被其他进程占满
正确做法是:写 → 检查失败 → 查
→ 分情况处理(
就清理/告警,
就改权限,
和
的处理策略完全不同)
析构时隐式
导致
覆盖是高频坑点
如果未显式调用
,
析构时会自动 flush 并 close。此时若发生
,
就在析构内部被覆盖,你根本来不及捕获。因此:
立即学习
“
C++免费学习笔记(深入)
”;
务必显式调用
,并在其后**立刻**检查
或使用 RAII 封装,在自定义析构中捕获失败(但需确保异常安全,避免在析构中抛异常)
更稳妥的做法是:每次
后都检查状态 +
,而不是等到最后
Linux 下还可配合
或
强制落盘并捕获早期错误,但会牺牲性能
磁盘满不是流状态机的一部分,它是操作系统内核返回的具体错误码。绕过
直接靠 C++ 流接口判断,等于在盲区里开车。
failbitbadbitstd::ofstreamfailbitbadbitflush()failbitbadbitwrite()EIOENOSPCerrnoerrnoENOSPCofstream!osos.fail()trueerrnoENOSPCerrnoerrnostd::ofstreamclear()errnoclose()errno#include ENOSPC_doserrno_doserrno == ERROR_HANDLE_DISK_FULLERROR_DISK_FULLstd::ofstream os("data.bin", std::ios::binary);
os.write(buf, size);
if (!os) {
int saved_errno = errno; // 必须立刻保存
if (saved_errno == ENOSPC) {
// 磁盘已满
}
}good()operator bool()good()!fail() && !bad() && !eof()os.seekp(0, std::ios::end); os.tellp()if (os.good()) os 来“预防”失败——这毫无意义statfs()GetDiskFreeSpaceEx()errnoENOSPCEACCESENOSPCEIOclose()errnoclose()ofstreamENOSPCerrnoos.close()errnowrite()errnosync_file_range()fdatasync()errno