Загрузка файла с помощью метода post() QNetworkAccessManager
у меня возникли проблемы с приложением Qt; в частности, с классом QNetworkAccessManager. Я пытаюсь выполнить простую HTTP-загрузку двоичного файла с помощью метода post () QNetworkAccessManager. В документации говорится, что я могу дать указатель на QIODevice to post () и что класс передаст данные, найденные в QIODevice. Это говорит мне о том, что я должен иметь возможность дать post() указатель на QFile. Для пример:
QFile compressedFile("temp");
compressedFile.open(QIODevice::ReadOnly);
netManager.post(QNetworkRequest(QUrl("http://mywebsite.com/upload") ), &compressedFile);
то, что, кажется, происходит в системе Windows, где я разрабатываю это, заключается в том, что мое приложение Qt выталкивает данные из QFile, но затем не завершает запрос; кажется, он сидит там, ожидая появления дополнительных данных из файла. Запрос post не "закрыт", пока я вручную не убью приложение, и в этот момент весь файл отображается на моем сервере.
из некоторых отладки и исследований я думаю, что это происходит потому, что операция read () QFile не возвращает -1, когда вы достигаете конца файла. Я думаю, что QNetworkAccessManager пытается читать из QIODevice, пока он не получит -1 от read (), в этот момент он предполагает, что больше нет данных и закрывает запрос. Если он продолжает получать нулевой код возврата из read (), QNetworkAccessManager предполагает, что может быть больше данных, и поэтому он продолжает ждать этих гипотетических данных.
Я подтвердил с некоторым тестовым кодом, что read () операция QFile просто возвращает ноль после того, как вы прочитали до конца файла. Это кажется несовместимым с тем, как метод post() QNetworkAccessManager ожидает, что QIODevice будет вести себя. Мои вопросы:
- это какое-то ограничение с тем, как QFile работает под Windows?
- есть ли другой способ использовать QFile или QNetworkAccessManager для перемещения файла через post()?
- это не собираюсь работайте вообще, и мне нужно будет найти другой способ загрузить мой файл?
любые предложения или советы будут оценены.
обновление: получается, что у меня две разные проблемы: одна на стороне клиента и на стороне сервера. На стороне клиента я должен был убедиться, что мой объект QFile оставался в течение всей сетевой транзакции. Метод post () QNetworkAccessManager возвращается немедленно, но на самом деле не завершен немедленно. Вам нужно прикрепить слот к сигналу finished () QNetworkAccessManager, чтобы определить, когда сообщение фактически завершено. В моем случае было достаточно легко сохранить QFile более или менее постоянно, но я также прикрепил слот к готовому сигналу (), чтобы проверить ответы на ошибки с сервера.
я прикрепил сигнал к слоту, как это:
connect(&netManager, SIGNAL(finished(QNetworkReply*) ), this, SLOT(postFinished(QNetworkReply*) ) );
когда пришло время отправить мой файл, я написал пост такой код (обратите внимание, что сжатый файл является членом моего класса и так не выйдут из области видимости после этого код):
compressedFile.open(QIODevice::ReadOnly);
netManager.post(QNetworkRequest(QUrl(httpDestination.getCString() ) ), &compressedFile);
завершенный(QNetworkReply*) сигнал от QNetworkAccessManager запускает мой метод postFinished(QNetworkReply*). Когда это произойдет, это безопасно для меня, чтобы закрыть сжатый файл и удалить файл данных, представленных сжатый файл. Для целей отладки я также добавил несколько операторов printf (), чтобы подтвердить, что транзакция завершена:
void CL_QtLogCompressor::postFinished(QNetworkReply* reply)
{
QByteArray response = reply->readAll();
printf("response: %sn", response.data() );
printf("reply error %dn", reply->error() );
reply->deleteLater();
compressedFile.close();
compressedFile.remove();
}
С compressedFile не закрывается сразу и не выходит за рамки, QNetworkAccessManager может занять столько времени, сколько ему нравится, чтобы передать мой файл. В конце концов транзакция завершена, и вызывается мой метод postFinished ().
моя другая проблема (которая также способствовала поведению, которое я видел, где транзакция никогда не завершалась) заключалась в том, что код Python для моего веб-сервера не заполнял сообщение правильно, но это выходит за рамки моего исходного Qt вопрос.
2 ответов
при создании compressedFile
в стеке и передача указателя на него вашему QNetworkRequest (и, в конечном счете, вашему QNetworkAccessManager). Как только вы оставите метод, в котором вы находитесь,compressedFile
выходит за рамки. Я удивлен, что это не рушится на вас, хотя поведение не определено.
вам нужно создать QFile
в куче:
QFile *compressedFile = new QFile("temp");
вам, конечно, нужно будет отслеживать его, а затем delete
это после того, как сообщение завершено, или установить его как дитя QNetworkReply
так что он будет уничтожен, когда ответ будет уничтожен позже:
QFile *compressedFile = new QFile("temp");
compressedFile->open(QIODevice::ReadOnly);
QNetworkReply *reply = netManager.post(QNetworkRequest(QUrl("http://mywebsite.com/upload") ), compressedFile);
compressedFile->setParent(reply);
вы также можете запланировать автоматическое удаление файла, выделенного кучей, с помощью сигналов / слотов
QFile* compressedFile = new QFile(...);
QNetworkReply* reply = Manager.post(...);
// This is where the tricks is
connect(reply, SIGNAL(finished()), reply, SLOT(deleteLater());
connect(reply, SIGNAL(destroyed()), compressedFile, SLOT(deleteLater());
IMHO, он гораздо более локализован и инкапсулирован, чем необходимость хранить файл во внешнем классе.
обратите внимание, что вы должны удалить первый элемент connect()
если у вас есть свой postFinished(QNetworkReply*)
слот, в который вы должны потом не забыть позвонить reply->deleteLater()
внутри него для выше, чтобы работать.