断点续传需用fstream以ios::in|ios::out|ios::binary打开,先seekg(0,ios::end)再tellg()获取长度,写前clear()并seekp(0,ios::end),验证tellp()与预期一致后write并flush(),进度存外部文件或原文件头,用uint64_t类型。

用 fstream 的 seekp 和 tellp 实现续传写入
断点续传写入本质是「在已有文件末尾(或指定位置)继续写,不覆盖、不重头」。C++ 标准库里没有现成的「断点续传」接口,但靠 fstream 的定位能力完全可以手动实现。关键不是“怎么打开”,而是“打开后怎么安全定位到上次写到哪”。
常见错误是直接用 ios::app 模式——它强制所有写入都在末尾,但无法得知当前文件长度;或者用 ios::in | ios::out 却忘了清空流状态,导致 tellp() 返回 -1。
-
fstream必须以ios::in | ios::out | ios::binary打开,缺一不可:读取旧内容需要in,写入需要out,二进制模式避免换行符干扰偏移计算 - 打开后立刻调用
seekg(0, ios::end)再tellg()获取当前长度,这就是续传起点;别依赖tellp()初始值——刚打开时它未定义 - 写入前务必调用
clear()清除可能存在的failbit(比如文件为空时seekg可能失败)
tellp 返回 -1 是什么情况?
tellp() 返回 -1 不代表“出错了”,只说明流处于无效状态(failbit 或 badbit 被置位)。最常见于:文件为空、打开失败、上一次操作失败未清理状态、或用了只读模式却调用 tellp。
组合式C++代码评审方案,融合静态分析、AI推理、多轮迭代评审和C++专项检查,适用于PR审查、增量代码审查、全项目评审和代码质量评分,触发词包括review cpp、cpp代码评审、C++review、代码审查。
- 检查
is_open()和good(),不要只看fail()——good()才表示一切就绪 - 如果文件为空,
seekg(0, ios::end)会成功,但tellg()返回 0;此时tellp()仍可能为 -1,必须先clear()再seekp(0, ios::end) - Windows 下用文本模式打开二进制文件,
tellp计算的字节数会因 CRLF 转换失真,务必坚持ios::binary
追加数据时如何避免覆盖或错位
续传的核心动作是「把写位置挪到文件末尾」,但不能简单用 ios::app——它会屏蔽你对位置的控制。正确做法是每次写前显式定位,并确认当前位置与预期一致。
- 写入前执行
seekp(0, ios::end),再用tellp()验证是否等于预期偏移(比如上次记录的进度);不等就说明文件被外部修改过,需告警而非强行续传 - 批量写入时,不要依赖多次
write()后的tellp()累加——系统缓冲或部分写入会导致偏差,应以单次write()后立刻tellp()为准 - 写入完成后立即
flush(),否则tellp()返回的是缓冲区偏移,不是实际落盘位置;尤其在程序可能崩溃的场景下,这步不能省
进度记录该存哪?存什么?
断点续传的“断点”信息必须持久化到文件外,否则重启即丢失。但别存成独立配置文件——多进程并发时容易冲突。最稳妥的是复用原文件头部(如前 8 字节)存已写入字节数。
- 用单独小文件存进度(如
xxx.progress)最简单,但要确保写入原子性:先写临时文件,再rename()覆盖,避免读到半截数据 - 若存原文件头部,必须用
seekp(0)写入,且写完立刻flush();同时首次创建文件时,头部默认填 0,后续只更新这个值 - 记录的值必须是
size_t或uint64_t,别用int——大文件超过 2GB 就溢出;读取时也用同样类型,避免符号扩展问题
真正麻烦的从来不是定位和写入,而是“怎么确认此刻的位置就是该续的地方”。外部篡改、缓存延迟、跨平台换行处理……这些细节不盯紧,tellp 返回的数字只是个幻觉。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!










