download 1GB file using QNetworkAccessManager, QN..Request, QN..Reply
-
I have a question:
How do you download a 1.3G file using QNetworkAccessManager and corresponding
QNetworkRequest and QNetworkReply classes?My app is generated using VS 2026 Insider and Qt 6.10.1 on laptop
with Windows 10 Home, Athlon with integreated graphics, 12GB memory;
which leaves approx 6GB memory free for the console app.This app works transfering 100's of smaller files without problem.
The app downloads approx 900MB of file before it terminates without error
when executed from command line; from VS 2026 the donload ends after approx 700MB.
It seems resources are being exhausted, as no error is displayed by the VS debugger.There seems to be a design flaw in releasing reply resouces after readready
processing of packets.
My initial thoughts: Are the multiple replies per request causing process
frame heap queue exhaustion? Does the reply api need some adjustment?How should this be handled properly????
I'm trying to follow best practices, yet no decent example for these classes exists.
I've built this after much web and ChatGPT quering and trial and error;
ChatGPT is how I learned about the classes initially.Below is the class definition:
/===========================================================================
**
** Copyright (C) 2025-present, William Bolish
**
** Contact: email: wwbolish1@gmail.com
**
** This is the license include file for Bolish Informatics software.
**
** Personal License
** This application software can be freely used personally.
** The user acknowledges any usage voids William Bolish from any
** damages this usage may entail, including any legal entanglement.
**
===========================================================================/
include <QtCore/QList>
#include <QtCore/QUrl>
#include <QtCore/QFile>
#include <QtCore/QByteArray>
#include <QtCore/QTemporaryFile>
#include <QtNetwork/QNetworkAccessManager>
#include <QtNetwork/QNetworkReply>
#include <QtNetwork/QSslError>#include "CollectItems.h"
class NetGetter : public QObject
{
Q_OBJECTpublic:
NetGetter(QNetworkAccessManager* theManager,
QObject *parent = nullptr);
~NetGetter();void issueRequest(CollectItems* theArgs); bool prcResponseData(); CollectItems *reqstArgs;private slots:
void onFinished(QNetworkReply *reply);
void onRedirected(const QUrl &url);
void onErrorOccurred(const QNetworkReply::NetworkError code);
void onSslErrors(const QList<QSslError> &sslErrs);
void onDownloadProgress(qint64 bytReceiv,
qint64 bytTotal);
void onReadyRead();private:
QNetworkAccessManager netManager;
QNetworkReply reply;
QUrl replyUrl;
QUrl redirectUrl;
QTemporaryFile* tmpFilObj;
QString tmpFilName;
int cntRplyPkts;
qint64 bytesReceived;
qint64 bytesTotal;
};#endif // NET_GETTER_H
Below is the class implementation:
/===========================================================================
**
** Copyright (C) 2025-present, William Bolish
**
** Contact: email: wwbolish1@gmail.com
**
** This is the license include file for Bolish Informatics software.
**
** Personal License
** This application software can be freely used personally.
** The user acknowledges any usage voids William Bolish from any
** damages this usage may entail, including any legal entanglement.
**
===========================================================================/
#include <QtCore/QTextStream>
#include <QtNetwork/QNetworkRequest>
#include <QtCore/QDebug>#include "NetGetter.h"
#include "NetHelpers.h"
#include "CompileDefs.h"
#include "ConstItems.h"
#include "ConsoleIo.h"const qint64 maxDownloadBuffer = sizGibibyte * 2;
/*!
** NetGetter is a cliet network worker for requesting and receiveing data.
**
** QNetWorkAccessManager handles the requests and its replys.
** It may issue the following signals and always the finished() lastly:
** void authenticationRequired(QNetworkReply *reply,
** QAuthenticator *authenticator)
** void encrypted(QNetworkReply *reply)
** void finished(QNetworkReply *reply)
** void preSharedKeyAuthenticationRequired(QNetworkReply *reply,
** QSslPreSharedKeyAuthenticator *authenticator)
** void proxyAuthenticationRequired(const QNetworkProxy &proxy,
** QAuthenticator *authenticator)
** void sslErrors(QNetworkReply *reply, const QList<QSslError> &errors)
**
** QNetworkRequest handles network requests.
** It does not issue any signals for the event manager to process.
**
** QNetworkReply handles network replies (responses to requests).
** It may issue the following signals and always the finished() lastly:
** void downloadProgress(qint64 bytesReceived,
** qint64 bytesTotal)
** void encrypted()
** void errorOccurred(QNetworkReply::NetworkError code)
** void finished()
** void metaDataChanged()
** void preSharedKeyAuthenticationRequired(QSslPreSharedKeyAuthenticator *authenticator)
** void redirectAllowed()
** void redirected(const QUrl &url)
** void requestSent() [since 6.3]
** void socketStartedConnecting() [since 6.3]
** void sslErrors(const QList<QSslError> &errors)
** void uploadProgress(qint64 bytesSent,
** qint64 bytesTotal)
** It also inherits the following signals from QIODevice
** void aboutToClose()
** void bytesWritten(qint64 bytes)
** void channelBytesWritten(int channel, qint64 bytes)
** void channelReadyRead(int channel)
** void readChannelFinished()
** void readyRead()
*/// Define request & reply strings.
const QString reqstStr = "!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!";
const QString replyStr = "$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$";/*!
Routine constructor.
Initialize the downloader class.For most cases, QSslConfiguration::defaultConfiguration() is sufficient and automatically handles system-provided certificates.*/
NetGetter::NetGetter(QNetworkAccessManager* theManager,
QObject *parent)
:
netManager(theManager),
QObject(parent)
{
reqstArgs = nullptr;tmpFilObj = new QTemporaryFile();}
/*!
Routine destructor.
Destroy the class.
*/NetGetter::~NetGetter()
{
delete tmpFilObj;
tmpFilObj = nullptr;delete netManager; netManager = nullptr; // reqstArgs is static item, will be eliminated on program closure; // just null pointer to it. reqstArgs = nullptr;}
// ##### REQUEST SEND #############################################################################
/*!
Routine request function.
Issue the network request.
*/void NetGetter::issueRequest(CollectItems *theArgs)
{
QString rtnName = "NetGetter::issueRequest";QString maskUrl; // Setup class info. // CollectItems::setItems sets: // theArgs->reqstSts to error seen. // theArgs->replySts to error seen. // theArgs->flgReplyFinished to false. // theArgs->flgEndListSeen to false. // reqstArgs->replyCnt to 0. // reqstArgs->replySiz to 0. // reqstArgs->getrErrorCode to 0. reqstArgs = theArgs; cntRplyPkts = 0; bytesReceived = 0; bytesTotal = -1; // Output request beginning statement. UrlHideCredentials(reqstArgs->reqestUrl, maskUrl); utility::displayMessageDebug(rtnName, QStringLiteral("\nREQ BEG %1 \n\t\t type=%2 url='%3'") .arg(reqstStr) .arg(reqstArgs->reqstTypeStr()) .arg(maskUrl)); // Setup request. QUrl theRequest(reqstArgs->reqestUrl); QNetworkRequest request(theRequest); request.setHeader(QNetworkRequest::UserAgentHeader, "QtApp"); // GitHub requires User-Agent // Set SSL configuration if specific requirements exist. QSslConfiguration sslConfiguration = QSslConfiguration::defaultConfiguration(); request.setSslConfiguration(sslConfiguration); // Setup signal handling. // Connect finished signal. connect(netManager, &QNetworkAccessManager::finished, this, &NetGetter::onFinished); // Show max redirects allowed. int maxRedirect = request.maximumRedirectsAllowed(); utility::displayMessageDebug(rtnName, QStringLiteral("maxRedirectsAllowed=%1") .arg(maxRedirect)); // Initialize variables. QString errMsg; QNetworkReply::NetworkError rpyErr; // Setup temporary file for response; // large response may overflow system memory. tmpFilObj->setFileTemplate("tempXXXXXX.tmp"); tmpFilObj->setAutoRemove(true); if (! tmpFilObj->open()) { errMsg = QStringLiteral("err=%1 desc='%2' \n\t %3.") .arg(tmpFilObj->error()) .arg(tmpFilObj->errorString()) .arg("Failed to open temp file for writing"); utility::displayMessageError(rtnName, errMsg); tmpFilName = ""; reqstArgs->getrErrorCode = tmpFilObj->error(); reqstArgs->replySts = netStsFileErr; reqstArgs->flgReplyFinished = true; goto reqxit; } else { tmpFilName = tmpFilObj->fileName(); } // if else // Issue reqest. reply = netManager->get(request); // Connect redirected signal to see redirect url. connect(reply, &QNetworkReply::redirected, this, &NetGetter::onRedirected); // Connect network error signal for errors. connect(reply, &QNetworkReply::errorOccurred, this, &NetGetter::onErrorOccurred); // Connect ssl error signal for SSL errors. connect(reply, &QNetworkReply::sslErrors, this, &NetGetter::onSslErrors); // Connect downloadd progress signal. connect(reply, &QNetworkReply::downloadProgress, this, &NetGetter::onDownloadProgress); // Connect ready to read signal. connect(reply, &QNetworkReply::readyRead, this, &NetGetter::onReadyRead); // Check for error. rpyErr = reply->error(); if (rpyErr == QNetworkReply::NoError) { utility::displayMessageDebug(rtnName, "Request success seen"); reqstArgs->reqstSts = netStsSuccess; } else { errMsg = QStringLiteral("error=%3 desc='%2'") .arg(reply->error()) .arg(reply->errorString()); utility::displayMessageCritical(rtnName, errMsg); reqstArgs->getrErrorCode = reply->error(); reqstArgs->reqstSts = netStsNetwkErr; if (tmpFilObj->isOpen()) tmpFilObj->close(); } // if elsereqxit:
utility::displayMessageDebug(rtnName, QStringLiteral("REQ END %1") .arg(reqstStr)); return;}
/*!
Routine slot function.
Handle redirected signal.
*/void NetGetter::onRedirected(const QUrl &url)
{
QString rtnName = "NetGetter::onRedirected";redirectUrl = url; utility::displayMessageInform(rtnName, QStringLiteral("reqstType=%1 redirected to '%2'") .arg(reqstArgs->reqstTypeStr()) .arg(url.toDisplayString()));}
/*!
Routine slot function.
Handle network error signal.
*/void NetGetter::onErrorOccurred(const QNetworkReply::NetworkError code)
{
QString rtnName = "NetGetter::onErrorOccurred";utility::displayMessageError(rtnName, QStringLiteral("%1: err=%2 desc='%3'") .arg("Network error occurred") .arg(code) .arg(reply->errorString())); reqstArgs->getrErrorCode = code; return;}
/*!
Routine slot function.
Handle ssl error signal.
*/void NetGetter::onSslErrors(const QList<QSslError> &sslErrs)
{
QString rtnName = "NetGetter::onSslErrors";utility::displayMessageError(rtnName, "SSL Errors encountered:"); for (const QSslError& sslErr : sslErrs) { QString errMsg = QStringLiteral("err=%1 desc='%2'") .arg(sslErr.error()) .arg(sslErr.errorString()); utility::displayIndentedMessage(2, utility::Error, errMsg); } // Return status may be handled by onFinished signal. // Finished boolean must be handled by onFinished signal. reqstArgs->replySts = netStsNetwkErr; return;}
/*!
Routine slot function.
Handle download progress signal.
*/void NetGetter::onDownloadProgress(qint64 bytReceiv,
qint64 bytTotal)
{
QString rtnName = "NetGetter::onDownloadProgress";// Increment the count of packets received. cntRplyPkts += 1; // Calculate bytes received this packet. qint64 pktBytes = bytReceiv - bytesReceived; bytesReceived = bytReceiv; utility::displayMessageDebug(rtnName, QStringLiteral("%1=%2 %3=%4 %5=%6 %7=%8") .arg("cntRplyPkts") .arg(cntRplyPkts) .arg("pktBytes") .arg(pktBytes) .arg("bytReceiv") .arg(bytReceiv) .arg("bytTotal") .arg(bytTotal)); // Return the bytesTotal; it is reported as -1 until all data is received. if (bytTotal > -1) { bytesTotal = bytTotal; utility::displayMessageInform(rtnName, QStringLiteral("%1=%2 %3=%4") .arg("cntRplyPkts") .arg(cntRplyPkts) .arg("bytesTotal") .arg(bytesTotal)); } return;}
/*!
Routine slot function.
Handle ready to read signal.
*/void NetGetter::onReadyRead()
{
QString rtnName = "NetGetter::onReadyRead";utility::displayMessageDebug(rtnName, QStringLiteral("bef cntRplyPkts=%1 size=%2") .arg(cntRplyPkts) .arg(reply->size())); QByteArray netInp = reply->readAll(); qint64 cntOut = tmpFilObj->write(netInp); utility::displayMessageDebug(rtnName, QStringLiteral("aft net.siz=%1 cntOut=%2 tmp.siz=%3 name=%4") .arg(netInp.size()) .arg(cntOut) .arg(tmpFilObj->size()) .arg(tmpFilObj->fileName())); return;}
// ##### REPLY FINISHED ###########################################################################
/*!
Routine slot function.
Handle the request finished signal and save the requested data;
i.e., handle the reply.
*/void NetGetter::onFinished(QNetworkReply *reply)
{
QString rtnName = "NetGetter::onFinished";QString maskUrl; // Update reply count. reqstArgs->replyCnt += 1; // Retrieve url of reply. replyUrl = reply->url(); // Display reply beginning string. UrlHideCredentials(reqstArgs->reqestUrl, maskUrl); utility::displayMessageDebug(rtnName, QStringLiteral("RPY BEG %1 \n\t\t type=%2 url='%3'") .arg(replyStr) .arg(reqstArgs->reqstTypeStr()) .arg(maskUrl)); UrlHideCredentials(replyUrl.toDisplayString(), maskUrl); utility::displayMessageDebug(rtnName, QStringLiteral("Reply_url='%1'") .arg(maskUrl)); // Retrieve reply headers for debug perusal. if (OUT_HDR_MSG) PrcHtmlHeaders(rtnName, reply, reqstArgs->replyCnt); bool rtnSts; // Check for no network reply error. QNetworkReply::NetworkError rpySts = reply->error(); if (rpySts != QNetworkReply::NoError) { QString errMsg = QStringLiteral("reqstType=%1 err=%2 \n\t\t desc='%3'" " \n\t\t url='%4'") .arg(reqstArgs->reqstTypeStr()) .arg(reply->error()) .arg(reply->errorString()) .arg(maskUrl); // 203 status doesn't seem to be a real error and transfers occur. // 299 status doesn't allow transfers but responses still come. // All empty data responses will generate message otherwise. if (rpySts != 203 && (rpySts == 499 && bytesTotal < 0) /*&& rpySts != 299*/ ) { // Process the error. utility::displayMessageError(rtnName, errMsg); reqstArgs->getrErrorCode = reply->error(); reqstArgs->replySts = netStsNetwkErr; reqstArgs->flgReplyFinished = true; goto rpyxit; } else { // Possibly process the warning. utility::displayMessageWarning(rtnName, errMsg); } } // if rpySts // The downloadProgress signal is completed before the finished signal, // therefore, the total data size is available currently. // // It looks like sometimes an empty reply is received. if (bytesTotal == 0) { utility::displayMessageDebug(rtnName, "No reply data received"); // For some reason, requests can send empty response(s) after a good response. // Just treat it as normal, no processing necessary. reqstArgs->replySts = netStsSuccess; goto rpyxit; } /* // For archive file, possibly change the output file name // to that used by the repository itself (with versioning info). // ??? Figure out how to obtain the repository file name. ??? if (reqstArgs->reqstType == ArchiveFile) { QFileInfo arcObj(reqstArgs->outputFilePath); QString arcFileName = arcObj.fileName(); QString replyFileName = replyUrl.fileName(); utility::displayMessageInform(rtnName, QStringLiteral("%1 '%2' to '%3'") .arg("Archive name replaced") .arg(arcFileName) .arg(replyFileName)); QString outFile = reqstArgs->outputFilePath.replace(arcFileName, replyFileName); reqstArgs->outputFilePath = outFile; } */ utility::displayMessageDebug(rtnName, "Reply received"); // Process the reply data. rtnSts = prcResponseData(/*reply, fileObj, responseData*/); if (! rtnSts) { // reqstArgs->replySts error already set reqstArgs->flgReplyFinished = true; goto rpyxit; } utility::displayMessageDebug(rtnName, QStringLiteral("Request&reply success \n\t\t %2 '%3'") .arg("Data saved to:") .arg(reqstArgs->outputFilePath)); utility::displayMessageDebug(rtnName, QStringLiteral("RPY END %1") .arg(replyStr)); // Indicate reply is finished. reqstArgs->replySts = netStsSuccess; reqstArgs->flgReplyFinished = true;rpyxit:
reply->deleteLater(); // Safe deletion return;}
/*!
Routine function.
For temp file: close, rename, make non-removable, delete dir entry.
*/void processTempFile(const QString prvPath,
const QString newPath,
QTemporaryFile* tmpFilObj)
{
QString rtnName = "processTempFile";// Rename the file. tmpFilObj->setAutoRemove(false); tmpFilObj->close(); bool renmSts = tmpFilObj->rename(newPath); // Remove temp file if not already done. bool exstSts = QFile::exists(prvPath); if (exstSts) QFile::remove(prvPath); utility::displayMessageInform(rtnName, QStringLiteral("renmSts=%1 exstSts=%2") .arg(renmSts) .arg(exstSts)); return;}
/*!
Routine function.
Process the reply response data.
*/bool NetGetter::prcResponseData()
{
QString rtnName = "NetGetter::prcResponseData";
bool rtnSts = false;utility::displayMessageInform(rtnName, QStringLiteral("tmpFilObj: name=%1 size=%2") .arg(tmpFilObj->fileName()) .arg(tmpFilObj->size())); // Process each request type. switch (reqstArgs->reqstType) { case FrontPage: case ListPage: case ArchivePage: { // Generate the html text file. processTempFile(tmpFilName, reqstArgs->outputFilePath, tmpFilObj); rtnSts = true; } break; case FrontMetadata: { // Mold response data into Json document. tmpFilObj->seek(0); QByteArray inpData = tmpFilObj->readAll(); QJsonDocument jsonDoc = QJsonDocument::fromJson(inpData); // Check for empty document. if (jsonDoc.isEmpty() || jsonDoc.isArray()) { utility::displayMessageError(rtnName, "The user json document has" " no meta-data"); reqstArgs->replySts = netStsBadJson; } else { // Obtain the json data and store the metadata. QJsonObject jsonObject = jsonDoc.object(); *reqstArgs->outputJsonObject = jsonObject; OutJsonObject(jsonObject, rtnName, "User meta-data"); // Output the meta-data to the file. tmpFilObj->resize(0); tmpFilObj->write(jsonDoc.toJson(QJsonDocument::Indented)); processTempFile(tmpFilName, reqstArgs->outputFilePath, tmpFilObj); rtnSts = true; } // if else jsonDoc } break; case ListMetadata: { // Mold response data into Json document. tmpFilObj->seek(0); QByteArray inpData = tmpFilObj->readAll(); QJsonDocument jsonDoc = QJsonDocument::fromJson(inpData); // Check for empty document. if (jsonDoc.isEmpty()) { utility::displayMessageError(rtnName, "The list json document has" " no meta-data"); reqstArgs->flgEndListSeen = true; rtnSts = true; } else { // The json document may or may not have an array of metadata. QJsonArray repoData; if (jsonDoc.isArray()) { repoData = jsonDoc.array(); } else if (jsonDoc.isObject()) { QJsonObject jsonObj = jsonDoc.object(); repoData.append(jsonObj); } // Store the json metadata. *reqstArgs->outputJsonArray = repoData; OutJsonArray(repoData, rtnName, "Page meta-data", reqstArgs->pageBaseCnt); // Output the meta-data to the file. tmpFilObj->resize(0); tmpFilObj->write(jsonDoc.toJson(QJsonDocument::Indented)); processTempFile(tmpFilName, reqstArgs->outputFilePath, tmpFilObj); rtnSts = true; } // if else jsonDoc } break; case ArchiveFile: { // Output the archive data to the file. processTempFile(tmpFilName, reqstArgs->outputFilePath, tmpFilObj); rtnSts = true; } break; } // switch return rtnSts;}
Below is output doing the file download:
@P @@@@@@@@@ RepoCollect in RetrieveRepos: Archive web page page=001
url='https://github.com/DeciHD/allwinner_docs'
file='_2025_12_29-github/+github.com+DeciHD/.../allwinner_docs.html'
@I ######### RepoCollect in NetGetter::onRedirected: reqstType='ArchiveFile' redirected to 'https://codeload.github.com/DeciHD/allwinner_docs/legacy.zip/refs/heads/main'
@I ######### RepoCollect in NetGetter::onDownloadProgress: cntRplyPkts=1 pktBytes=32768 bytReceiv=32768 bytTotal=-1
@I ######### RepoCollect in NetGetter::onDownloadProgress: cntRplyPkts=2 pktBytes=86016 bytReceiv=118784 bytTotal=-1
@I ######### RepoCollect in NetGetter::onDownloadProgress: cntRplyPkts=3 pktBytes=1424816 bytReceiv=1543600 bytTotal=-1
@I ######### RepoCollect in NetGetter::onDownloadProgress: cntRplyPkts=4 pktBytes=2880954 bytReceiv=4424554 bytTotal=-1
@I ######### RepoCollect in NetGetter::onDownloadProgress: cntRplyPkts=5 pktBytes=2989206 bytReceiv=7413760 bytTotal=-1
@I ######### RepoCollect in NetGetter::onDownloadProgress: cntRplyPkts=6 pktBytes=4694890 bytReceiv=12108650 bytTotal=-1
@I ######### RepoCollect in NetGetter::onDownloadProgress: cntRplyPkts=7 pktBytes=5410090 bytReceiv=17518740 bytTotal=-1
@I ######### RepoCollect in NetGetter::onDownloadProgress: cntRplyPkts=8 pktBytes=3580912 bytReceiv=21099652 bytTotal=-1
@I ######### RepoCollect in NetGetter::onDownloadProgress: cntRplyPkts=9 pktBytes=3768320 bytReceiv=24867972 bytTotal=-1
@I ######### RepoCollect in NetGetter::onDownloadProgress: cntRplyPkts=10 pktBytes=3997696 bytReceiv=28865668 bytTotal=-1
@I ######### RepoCollect in NetGetter::onDownloadProgress: cntRplyPkts=11 pktBytes=4505600 bytReceiv=33371268 bytTotal=-1
@I ######### RepoCollect in NetGetter::onDownloadProgress: cntRplyPkts=12 pktBytes=5225520 bytReceiv=38596788 bytTotal=-1
@I ######### RepoCollect in NetGetter::onDownloadProgress: cntRplyPkts=13 pktBytes=5732553 bytReceiv=44329341 bytTotal=-1
@I ######### RepoCollect in NetGetter::onDownloadProgress: cntRplyPkts=14 pktBytes=3306855 bytReceiv=47636196 bytTotal=-1
@I ######### RepoCollect in NetGetter::onDownloadProgress: cntRplyPkts=15 pktBytes=3342336 bytReceiv=50978532 bytTotal=-1
@I ######### RepoCollect in NetGetter::onDownloadProgress: cntRplyPkts=16 pktBytes=2531363 bytReceiv=53509895 bytTotal=-1
@I ######### RepoCollect in NetGetter::onDownloadProgress: cntRplyPkts=17 pktBytes=3620864 bytReceiv=57130759 bytTotal=-1
@I ######### RepoCollect in NetGetter::onDownloadProgress: cntRplyPkts=18 pktBytes=3743993 bytReceiv=60874752 bytTotal=-1
@I ######### RepoCollect in NetGetter::onDownloadProgress: cntRplyPkts=19 pktBytes=3141632 bytReceiv=64016384 bytTotal=-1
@I ######### RepoCollect in NetGetter::onDownloadProgress: cntRplyPkts=20 pktBytes=3988309 bytReceiv=68004693 bytTotal=-1
@I ######### RepoCollect in NetGetter::onDownloadProgress: cntRplyPkts=21 pktBytes=4072558 bytReceiv=72077251 bytTotal=-1
@I ######### RepoCollect in NetGetter::onDownloadProgress: cntRplyPkts=22 pktBytes=1341677 bytReceiv=73418928 bytTotal=-1
@I ######### RepoCollect in NetGetter::onDownloadProgress: cntRplyPkts=23 pktBytes=4324785 bytReceiv=77743713 bytTotal=-1
...
...
...
@I ######### RepoCollect in NetGetter::onDownloadProgress: cntRplyPkts=310 pktBytes=1215786 bytReceiv=991757964 bytTotal=-1
@I ######### RepoCollect in NetGetter::onDownloadProgress: cntRplyPkts=311 pktBytes=4340605 bytReceiv=996098569 bytTotal=-1
@I ######### RepoCollect in NetGetter::onDownloadProgress: cntRplyPkts=312 pktBytes=1848087 bytReceiv=997946656 bytTotal=-1
@I ######### RepoCollect in NetGetter::onDownloadProgress: cntRplyPkts=313 pktBytes=4343270 bytReceiv=1002289926 bytTotal=-1
@I ######### RepoCollect in NetGetter::onDownloadProgress: cntRplyPkts=314 pktBytes=4404474 bytReceiv=1006694400 bytTotal=-1
@I ######### RepoCollect in NetGetter::onDownloadProgress: cntRplyPkts=315 pktBytes=2482303 bytReceiv=1009176703 bytTotal=-1
@I ######### RepoCollect in NetGetter::onDownloadProgress: cntRplyPkts=316 pktBytes=3301249 bytReceiv=1012477952 bytTotal=-1
@I ######### RepoCollect in NetGetter::onDownloadProgress: cntRplyPkts=317 pktBytes=2342948 bytReceiv=1014820900 bytTotal=-1
@I ######### RepoCollect in NetGetter::onDownloadProgress: cntRplyPkts=318 pktBytes=3595225 bytReceiv=1018416125 bytTotal=-1
@I ######### RepoCollect in NetGetter::onDownloadProgress: cntRplyPkts=319 pktBytes=3620864 bytReceiv=1022036989 bytTotal=-1
@I ######### RepoCollect in NetGetter::onDownloadProgress: cntRplyPkts=320 pktBytes=3801088 bytReceiv=1025838077 bytTotal=-1
@I ######### RepoCollect in NetGetter::onDownloadProgress: cntRplyPkts=321 pktBytes=3400120 bytReceiv=1029238197 bytTotal=-1
@I ######### RepoCollect in NetGetter::onDownloadProgress: cntRplyPkts=322 pktBytes=4070674 bytReceiv=1033308871 bytTotal=-1
@I ######### RepoCollect in NetGetter::onDownloadProgress: cntRplyPkts=323 pktBytes=3137715 bytReceiv=1036446586 bytTotal=-1
@I ######### RepoCollect in NetGetter::onDownloadProgress: cntRplyPkts=324 pktBytes=4407296 bytReceiv=1040853882 bytTotal=-1
@I ######### RepoCollect in NetGetter::onDownloadProgress: cntRplyPkts=325 pktBytes=3018966 bytReceiv=1043872848 bytTotal=-1
@I ######### RepoCollect in NetGetter::onDownloadProgress: cntRplyPkts=326 pktBytes=3227484 bytReceiv=1047100332 bytTotal=-1
@I ######### RepoCollect in NetGetter::onDownloadProgress: cntRplyPkts=327 pktBytes=3294292 bytReceiv=1050394624 bytTotal=-1
@I ######### RepoCollect in main: Run ended: time='_2025-12-29 15:20:33' duration='0d 0: 1: 2' -
Hi @wwbolish
In general
QNetworkResponsedoesn't hold on to data which was already read, and tries to not buffer more than the configured read buffer. If your program is running out of memory downloading large files, then something in it is holding on to data more than needed.Unfortunately, it is very hard to help you figure out the reason since the code is poorly formatted in the forum post and is too long. Make sure that each file is fully contained in a single code block, and try to reduce it as much as possible (e.g. we certainly don't need full copyright notices and documentation comments, commented out code or unused member variables).
-
Also when downloading 1GB I would save it to a QFile as soon as some parts arrived - connect https://doc.qt.io/qt-6/qiodevice.html#readyRead and save the already downloaded parts.
-
In the readyRead slot, it is best to put a loop:
while (reply->bytesAvailable() > 0) { QByteArray netInp = reply->readAll(); qint64 cntOut = tmpFilObj->write(netInp); }If more data arrives while you are processing/saving the block of data received, the readyRead signal is not repeated. That is why you are getting larger and larger blocks of data with each signal.