切换读写方向前必须 flush 或 sync,因 fstream 共用缓冲区,方向切换时需显式同步;仅 ios::in|ios::out 模式支持双向操作;seekg/seekp 各自维护偏移;文本模式下换行符映射会导致定位失准,须用 binary 模式。

切换读写方向前必须 flush 或 sync
用 fstream 同时读写一个文件时,底层共用一个缓冲区。如果刚写完几字节就立刻调用 seekg() 去读,旧写入可能还卡在缓冲区没落盘,seekg() 会定位到“逻辑文件位置”,但读出来的可能是未刷新的旧数据或乱码。
标准做法是:每次从写切到读、或从读切到写之前,显式调用 flush()(对输出缓冲);若支持,也可调用 sync()(同步整个流缓冲)。C++17 起 sync() 是更稳妥的选择,它强制同步输入/输出缓冲与实际文件偏移。
-
ofstream和ifstream不支持双向切换,只有fstream可以,且必须显式指定ios::in | ios::out - 即使只用
seekg()或seekp()移动指针,不执行 I/O,也建议在方向切换前 flush —— 因为缓冲区状态和文件指针可能已不同步 - Windows 下某些 CRT 实现对
sync()支持不完整,此时应组合使用flush()+seekg(0, ios::cur)强制重置读位置
open 模式决定是否允许读写混用
如果打开时只写了 ios::out,哪怕对象是 fstream,后续调用 seekg() 或 read() 也会失败(failbit 置位)。同样,仅用 ios::in 打开后不能写。
真正支持读写切换的唯一合法模式是同时包含 ios::in 和 ios::out,例如:
fstream fs("data.bin", ios::in | ios::out | ios::binary);
-
ios::trunc会清空文件,慎用于读写混合场景;如需保留原内容,不要加它 -
ios::ate会让文件指针初始定位到末尾,但不影响读写能力,只是起始位置不同 - 用
ios::app时,所有写操作强制追加,seekp()对写位置无效 —— 此时无法真正“随机写”
seekg 和 seekp 的行为差异容易混淆
seekg() 控制“获取”(get)位置,即下一次 read() 或 getline() 的起点;seekp() 控制“放置”(put)位置,即下一次 write() 或 的起点。它们各自维护独立的偏移量,互不影响。
- 调用
seekg(pos)不会改变seekp()当前值,反之亦然 - 若想让读写指针一致,需分别调用:
fs.seekg(pos); fs.seekp(pos); - 用
seekg(0, ios::end)获取文件大小后,若紧接着要写,记得再调用seekp(0, ios::end),否则写入仍从开头开始
二进制模式下换行符不会被转换,但文本模式会干扰定位
在文本模式(默认)下,Windows 的 \r\n 会被读作单个 \n,而写入时又自动补回 \r\n。这导致 seekg() 的字节偏移和实际内容长度不一致 —— 你 seek 到第 10 字节,可能只读到了第 9 个逻辑字符。
只要涉及精确跳转(比如解析固定结构的记录、修改某块二进制字段),必须用 ios::binary 模式打开。
- 文本模式下
gcount()返回的字节数 ≠ 实际读取的字符数(因换行符映射) - 二进制模式下
seekg()和seekp()的参数是真实字节偏移,可信赖 - 即使文件内容全是 ASCII,只要需要 seek 定位,就该用 binary 模式,而不是依赖“看起来没问题”
seekg() 就成了幻觉操作。C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!











