Загрузка файла с помощью сообщения () метод QNetworkAccessManager

Я испытываю некоторые затруднения из-за спокойного приложения; конкретно с классом QNetworkAccessManager. Я пытаюсь выполнить простую загрузку HTTP двоичного файла с помощью сообщения () метод QNetworkAccessManager. Документация указывает, что я могу дать подсказку к QIODevice для регистрации (), и что класс передаст данные, найденные в QIODevice. Это предлагает мне, чтобы я должен был смочь дать сообщение () указатель на QFile. Например:

QFile compressedFile("temp");  
compressedFile.open(QIODevice::ReadOnly);  
netManager.post(QNetworkRequest(QUrl("http://mywebsite.com/upload") ), &compressedFile);  

Что, кажется, происходит в системе Windows, где я разрабатываю, это - то, что мое спокойное приложение продвигает данные из QFile, но затем не завершает запрос; это, кажется, находится, там ожидая большего количества данных для разоблачения из файла. Запрос сообщения не "закрывается", пока я вручную не уничтожаю приложение, в которой точке целый файл обнаруживается в моем конце сервера.

От некоторой отладки и исследования, я думаю, что это происходит, потому что чтение () операция QFile не возвращается-1 при достижении конца файла. Я думаю, что QNetworkAccessManager пытается читать из QIODevice, пока это не получает-1 от чтения (), в которой точке он предполагает, что больше нет данных и не закрывают запрос. Если это продолжает получать код возврата нуля от чтения (), QNetworkAccessManager предполагает, что могло бы быть больше прибытия данных, и таким образом, это заставляет ждать те гипотетические данные.

Я подтвердил с некоторым тестовым кодом, что чтение () операция QFile просто возвращает нуль после чтения в конец файла. Это, кажется, является несовместимым со способом, которым сообщением () метод QNetworkAccessManager ожидает, что QIODevice будет вести себя. Мои вопросы:

  1. Это своего рода ограничение со способом, которым QFile работает в соответствии с Windows?
  2. Есть ли некоторый другой способ, которым я должен использовать или QFile или QNetworkAccessManager для продвижения файла по почте ()?
  3. Разве это не собирается работать вообще, и я должен буду найти некоторый другой способ загрузить мой файл?

Любые предложения или подсказки ценились бы.

Обновление: оказывается, что у меня было две различных проблемы: один на стороне клиента и один на стороне сервера. На стороне клиента я должен был удостовериться, что мой объект QFile остался вокруг на время сетевой транзакции. Сообщение () метод QNetworkAccessManager сразу возвращается, но на самом деле сразу не закончен. Необходимо присоединить слот к законченному () сигнал QNetworkAccessManager определить, когда POST на самом деле закончен. В моем случае было достаточно легко иметь в наличии QFile более или менее постоянно, но я также присоединил слот к законченному () сигнал для проверки на ошибочные ответы с сервера.

Я присоединил сигнал к слоту как это:

connect(&netManager, SIGNAL(finished(QNetworkReply*) ), this, SLOT(postFinished(QNetworkReply*) ) );  

Когда пришло время отправить мой файл, я записал, почтовый индекс как это (обратите внимание, что compressedFile является членом моего класса и так не выходит из объема после этого кода):

compressedFile.open(QIODevice::ReadOnly);  
netManager.post(QNetworkRequest(QUrl(httpDestination.getCString() ) ), &compressedFile);  

Законченный (QNetworkReply*) сигнал от QNetworkAccessManager инициировал мой постзаконченный (QNetworkReply*) метод. Когда это происходит, для меня безопасно закрыть compressedFile и удалить файл данных, представленный compressedFile. Для отладки целей я также добавил несколько printf () операторы, чтобы подтвердить, что транзакция является завершенной:

void CL_QtLogCompressor::postFinished(QNetworkReply* reply)  
{  
    QByteArray response = reply->readAll();  
    printf("response: %s\n", response.data() );  
    printf("reply error %d\n", reply->error() );  
    reply->deleteLater();  
    compressedFile.close();  
    compressedFile.remove();  
}  

Так как compressedFile сразу не закрывается и не выходит из объема, QNetworkAccessManager может занять столько времени, сколько ему нравится передавать мой файл. В конечном счете транзакция является завершенной и мой постзаконченный (), метод называют.

Моя другая проблема (который также способствовал поведению, которое я видел, где транзакция, никогда не завершаемая), состояла в том, что код Python для моего веб-сервера не выставлял POST правильно, но это выходит за рамки моего исходного спокойного вопроса.

7
задан dbisdorf 14 July 2010 в 13:07
поделиться

2 ответа

Вы создаете compressedFile в стеке и передаете указатель на него вашему QNetworkRequest (и, в конечном итоге, вашему QNetworkAccessManager). Как только вы покидаете метод, в котором находитесь, compressedFile выходит за пределы области видимости. Я удивлен, что он не падает на вас, хотя поведение не определено.

Вам необходимо создать QFile в куче:

QFile *compressedFile = new QFile("temp"); 

Вам, конечно, нужно будет отслеживать его, а затем удалить после завершения публикации или установить это как дочерний элемент QNetworkReply , так что он будет уничтожен, когда ответ будет уничтожен позже:

QFile *compressedFile = new QFile("temp"); 
compressedFile->open(QIODevice::ReadOnly);

QNetworkReply *reply = netManager.post(QNetworkRequest(QUrl("http://mywebsite.com/upload") ), compressedFile); 
compressedFile->setParent(reply);
8
ответ дан 6 December 2019 в 23:02
поделиться

Вы также можете запланировать автоматическое удаление файла, выделенного на куче, используя сигналы/слоты

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());

ИМХО, это гораздо более локализовано и инкапсулировано, чем необходимость держать вокруг себя файл во внешнем классе.

Обратите внимание, что вы должны удалить первый connect(), если у вас есть ваш postFinished(QNetworkReply*) слот, в котором вы должны затем не забыть вызвать reply->deleteLater() внутри него, чтобы вышеописанное работало.

3
ответ дан 6 December 2019 в 23:02
поделиться
Другие вопросы по тегам:

Похожие вопросы: