如何用C++和Qt正确计算文件下载速度?
解决Qt下载速度计算持续增长的问题
问题根源
当前代码计算的是累计平均下载速度(总下载字节数 ÷ 总耗时),而非实时瞬时速度。随着下载进行,总字节数和总耗时同步增加,数值会一直向平均速率靠拢,无法反映当前真实的下载快慢。
解决方案
通过记录上一次回调的字节数和时间戳,计算两次downloadProgress回调之间的字节增量与时间增量,用增量比值得到这段时间内的瞬时速度,就能准确反映实时下载速率。
修改后的完整代码
class FileDownloader : public QObject { Q_OBJECT public: QNetworkAccessManager *manager; QByteArray downloadedData; QElapsedTimer downloadTimer; qint64 lastBytesRead = 0; // 记录上一次的已下载字节数 qint64 lastTimeMs = 0; // 记录上一次的时间戳(毫秒) FileDownloader(const QUrl &url) { manager = new QNetworkAccessManager(this); QNetworkRequest request(url); QNetworkReply* reply = manager->get(request); connect(reply, &QNetworkReply::readyRead, this, [=] { downloadedData.append(reply->readAll()); if (!downloadTimer.isValid()) downloadTimer.start(); }); connect(reply, &QNetworkReply::downloadProgress, this, [this](qint64 bytesRead, qint64 totalBytes) { int perc = 0; if (totalBytes) perc = static_cast<int>((bytesRead * 100) / totalBytes); qDebug().nospace() << "\n" << perc << "% (" << bytesRead << "/" << totalBytes << ")"; qint64 currentTimeMs = downloadTimer.elapsed(); // 跳过第一次回调(无增量可计算) if (lastTimeMs > 0 && currentTimeMs > lastTimeMs) { qint64 bytesDelta = bytesRead - lastBytesRead; qint64 timeDeltaMs = currentTimeMs - lastTimeMs; // 计算瞬时速度(字节/秒) double speedBytesPerSec = bytesDelta / (timeDeltaMs / 1000.0); // 转换为常用单位(注:这里用1000进制,若需二进制单位可替换为1024) double speedKbps = speedBytesPerSec * 8 / 1000; double speedMbps = speedKbps / 1000; QString speedUnit; double speedValue; if (speedMbps >= 1.0) { speedUnit = "MB/s"; speedValue = speedMbps; } else { speedUnit = "KB/s"; speedValue = speedKbps; } qDebug().noquote() << "Download Speed:" << QString::number(speedValue, 'f', 2) << speedUnit; } // 更新上一次的记录值 lastBytesRead = bytesRead; lastTimeMs = currentTimeMs; }); } }; int main(int argc, char *argv[]) { QApplication a(argc, argv); QUrl url( "https://go.microsoft.com/fwlink/p/?LinkID=2208844&clcid=0x409&culture=en-us&country=US"); FileDownloader fileDownloader(url); return a.exec(); }
关键修改说明
- 添加
lastBytesRead和lastTimeMs成员变量,用于存储上一次回调的状态 - 在
downloadProgress中,仅当存在有效时间增量时计算速度,避免第一次回调的无效计算 - 用
bytesDelta(字节增量)和timeDeltaMs(时间增量)计算瞬时速度,而非总总量除以总时间 - 每次回调结束后更新记录值,为下一次计算做准备
内容的提问来源于stack exchange,提问作者Nina
相关产品推荐
相关产品推荐

