用 std::ofstream 以 std::ios::app 模式打开文件即可追加写入;该模式隐含 std::ios::out,自动将每次写入定位到文件末尾,无需手动 seekp(),而 std::ios::ate 仅初始定位末尾但不自动追加。

用 std::ofstream 以 std::ios::app 模式打开文件即可追加写入
这是最直接、最可靠的方式。C++ 标准库不提供“追加写入函数”,而是通过控制文件流的打开模式来实现——只要用 std::ios::app,所有写入操作都会自动定位到文件末尾,无需手动 seekp()。
常见错误是误用 std::ios::ate(定位到末尾但不自动追加)或忘记指定 std::ios::out(只写模式必须显式声明):
-
std::ofstream f("log.txt", std::ios::app)✅ 正确:隐含out,每次写都追加 -
std::ofstream f("log.txt", std::ios::ate)❌ 错误:只是打开时定位到末尾,后续仍从当前位置覆盖写 -
std::ofstream f("log.txt", std::ios::app | std::ios::in)❌ 可能失败:多数系统不支持对追加模式流进行读操作
追加写入时要注意换行符和缓冲区行为
追加不是“智能续行”——如果原文件末尾没有换行符,新内容会紧贴上一行末尾写入,容易导致日志混行。
另外,std::ofstream 默认带缓冲,程序崩溃或未正常关闭流时,最后几条日志可能丢失:
- 写入后调用
f.flush()强制刷盘(适合关键日志) - 避免在循环中频繁开/关文件;应保持流打开,多次写入后统一关闭
- 若需每行日志立即落盘,可设无缓冲:
f.rdbuf()->pubsetbuf(nullptr, 0),但会显著降低性能
多线程环境下不能直接共享同一个 std::ofstream
std::ofstream 对象不是线程安全的。多个线程同时调用 或 <code>write(),会导致输出错乱甚至崩溃。
可行方案只有两种:
- 用互斥锁保护写入操作(简单但有竞争)
- 每个线程独占一个文件流(推荐用于日志分离场景,如按线程 ID 命名文件)
- 完全避免共享——改用原子写入系统调用(如 Linux 的
open(..., O_APPEND)+write()),此时内核保证追加原子性
Windows 下用 std::ios::binary 避免换行符被悄悄转换
在 Windows 默认文本模式下,写入 '\n' 会被转成 "\r\n",而 std::ios::app 模式下这个转换仍会发生。如果追加内容来自其他平台或需精确字节控制(如写二进制日志头),必须加 std::ios::binary:
std::ofstream f("data.bin", std::ios::app | std::ios::binary);
f.write(buf, size); // 不做任何字符转换
注意:一旦用了 binary,就不能再用 写字符串(会触发隐式转换),必须用 <code>write() 或确保数据已按需编码。
追加写入真正麻烦的从来不是“怎么写”,而是“谁在写、什么时候写完、写完有没有真落盘”。模式选错、缓冲失控、线程争抢、跨平台换行,任何一个点没控住,日志就丢或者串行了。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!











