qt中用qnetworkaccessmanager实现分片下载的关键点是:必须手动组合qnetworkrequest与qnetworkreply,通过head请求校验accept-ranges支持,用range头指定字节范围,预分配文件空间后seek+write精准落盘,持久化记录completedranges,控制并发与超时重试,并校验服务端last-modified防止断点失效。

Qt 中用 QNetworkAccessManager 实现分片下载的关键点
Qt 本身不提供原生的断点续传或分片下载封装,必须手动组合 QNetworkRequest、QNetworkReply 和 HTTP Range 头。核心是:每次请求只取文件某一段,且能从上次中断位置继续——这依赖服务端支持 Accept-Ranges: bytes 和正确响应 206 Partial Content。
常见错误是直接用 QNetworkAccessManager::get() 发起全量请求后强行中断,再重发——这样无法复用已下载数据,也不算真正断点续传。
- 务必先 HEAD 请求目标 URL,检查响应头是否含
Accept-Ranges: bytes,并读取Content-Length - 用
QNetworkRequest::setRawHeader("Range", "bytes=1024-2047")指定字节范围(注意:Range 值从 0 开始计数) - 不要用
QFile::append写入;必须用QFile::write()配合QFile::seek()定位到指定偏移写入,否则会覆盖或错位 - 每个分片应独立管理状态(起始偏移、期望长度、实际写入长度),避免因网络抖动导致局部错乱
如何安全拼接多个分片到一个文件
分片写入不是简单追加,而是按原始文件偏移精准落盘。典型做法是预先创建一个大小为 Content-Length 的空文件(用 QFile::resize()),再逐个分片 seek + write。
容易踩的坑:Windows 下用 QFile::open(..., QIODevice::Append) 后调用 seek() 可能失败;必须用 QIODevice::ReadWrite 模式打开,且确保文件已存在并预分配空间。
- 创建临时文件时,先
file.open(QIODevice::WriteOnly),file.resize(totalSize),再file.close() - 每个分片下载完成回调中:打开文件(
QIODevice::ReadWrite),file.seek(startOffset),file.write(data),立刻file.flush() - 避免用内存缓冲整个分片再写入——大文件下易 OOM;应边接收边
write()到文件对应位置
断点状态持久化与恢复逻辑怎么设计
程序崩溃或用户关闭后,必须记住哪些分片已完成、哪些失败、当前总进度。不能只靠内存变量,得落地到磁盘。
推荐用轻量 JSON 文件记录,字段至少包含:url、totalSize、completedRanges(数组,每项为 {start: 0, end: 1023})、lastModified。别用 SQLite 或复杂序列化——增加可靠性负担。
- 每次成功写入一个分片后,立即更新 JSON 并
QFile::flush()+QFile::close() - 启动恢复时,先读 JSON,对比本地文件大小和
completedRanges,跳过已完整写入的区间 - 注意时间戳校验:如果服务端文件被更新(
Last-Modified变了),原有断点数据可能失效,需清空重下
QNetworkReply 超时、重试、并发控制的实际处理
分片越多,并发请求数越高,越容易触发服务端限流或本地 socket 耗尽。Qt 默认不限制并发,必须自己控。
单纯用 connect(reply, &QNetworkReply::finished, ...) 不足以应对超时或重定向失败——finished() 仅表示连接结束,不保证成功;要同时监听 errorOccurred() 和检查 reply->attribute(QNetworkRequest::HttpStatusCodeAttribute)。
- 为每个分片 reply 设置独立超时(用
QTimer单独监控,因为QNetworkReply无内置超时) - 重试最多 2 次,且指数退避(如第 1 次等 1s,第 2 次等 2s),避免雪崩
- 限制最大并发分片数(如 3–5 个),用信号槽队列或
QSemaphore控制,别一股脑发几十个请求 - 收到
416 Requested Range Not Satisfiable表示 Range 错误,需重新 HEAD 获取最新Content-Length
分片下载真正的难点不在 Qt API 调用,而在状态一致性:网络不可靠、磁盘可能满、用户随时取消、服务端策略变更——所有这些都得在单个分片粒度上可验证、可回滚、可对齐。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!











