使用QNetworkAccessManager的post()方法上传文件 [英] Uploading a file using post() method of QNetworkAccessManager

查看:520
本文介绍了使用QNetworkAccessManager的post()方法上传文件的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我在使用Qt应用程序时遇到了一些麻烦;特别是QNetworkAccessManager类。我正在尝试使用QNetworkAccessManager的post()方法执行二进制文件的简单HTTP上载。文档声明我可以将指向QIODevice的指针发送到post(),并且该类将传输在QIODevice中找到的数据。这告诉我,我应该能够给post()一个指向QFile的指针。例如:

I'm having some trouble with a Qt application; specifically with the QNetworkAccessManager class. I'm attempting to perform a simple HTTP upload of a binary file using the post() method of the QNetworkAccessManager. The documentation states that I can give a pointer to a QIODevice to post(), and that the class will transmit the data found in the QIODevice. This suggests to me that I ought to be able to give post() a pointer to a QFile. For example:

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

在我开发这个系统的Windows系统上似乎发生的事情是我的Qt应用程序推动了来自QFile的数据,但随后没有完成请求;它似乎坐在那里等待从文件中显示更多数据。在我手动终止应用程序之前,post请求不会关闭,此时整个文件显示在我的服务器端。

What seems to happen on the Windows system where I'm developing this is that my Qt application pushes the data from the QFile, but then doesn't complete the request; it seems to be sitting there waiting for more data to show up from the file. The post request isn't "closed" until I manually kill the application, at which point the whole file shows up at my server end.

从一些调试和研究中,我认为这种情况正在发生,因为当你到达文件末尾时,QFile的read()操作不会返回-1。我认为QNetworkAccessManager试图从QIODevice读取,直到它从read()获得-1,此时它假定没有更多数据并关闭请求。如果它继续从read()获得零返回码,QNetworkAccessManager假定可能有更多数据到来,所以它一直在等待那个假设数据。

From some debugging and research, I think this is happening because the read() operation of QFile doesn't return -1 when you reach the end of the file. I think that QNetworkAccessManager is trying to read from the QIODevice until it gets a -1 from read(), at which point it assumes there is no more data and closes the request. If it keeps getting a return code of zero from read(), QNetworkAccessManager assumes that there might be more data coming, and so it keeps waiting for that hypothetical data.

I已经通过一些测试代码确认QFile的read()操作在读到文件末尾后才返回零。这似乎与QNetworkAccessManager的post()方法期望QIODevice的行为方式不兼容。我的问题是:

I've confirmed with some test code that the read() operation of QFile just returns zero after you've read to the end of the file. This seems to be incompatible with the way that the post() method of QNetworkAccessManager expects a QIODevice to behave. My questions are:


  1. QFile在Windows下的工作方式是否有某种限制?

  2. 还有其他方法我应该使用QFile或QNetworkAccessManager通过post()推送文件吗?

  3. 这根本不起作用,我必须找到上传我的文件的其他方式?

任何建议或提示都将不胜感激。

Any suggestions or hints would be appreciated.

更新:事实证明我遇到了两个不同的问题:一个在客户端,另一个在服务器端。在客户端,我必须确保我的QFile对象在网络事务期间保持不变。 QNetworkAccessManager的post()方法立即返回,但实际上并未立即完成。您需要将一个槽附加到QNetworkAccessManager的finished()信号,以确定POST何时实际完成。在我的情况下,很容易将QFile保持在或多或少永久,但我还在finish()信号上附加了一个插槽,以检查来自服务器的错误响应。

Update: It turns out that I had two different problems: one on the client side and one on the server side. On the client side, I had to ensure that my QFile object stayed around for the duration of the network transaction. The post() method of QNetworkAccessManager returns immediately but isn't actually finished immediately. You need to attach a slot to the finished() signal of QNetworkAccessManager to determine when the POST is actually finished. In my case it was easy enough to keep the QFile around more or less permanently, but I also attached a slot to the finished() signal in order to check for error responses from the server.

我将信号附加到插槽如下:

I attached the signal to the slot like this:

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

当发送我的文件时,我写了这样的邮政编码(请注意,compressedFile是我的类的成员,因此在此代码之后不会超出范围):

When it was time to send my file, I wrote the post code like this (note that compressedFile is a member of my class and so does not go out of scope after this code):

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

来自QNetworkAccessManager的完成(QNetworkReply *)信号触发我的postFinished(QNetworkReply *)方法。发生这种情况时,我可以安全地关闭compressedFile并删除co​​mpressedFile表示的数据文件。出于调试目的,我还添加了一些printf()语句来确认事务已完成:

The finished(QNetworkReply*) signal from QNetworkAccessManager triggers my postFinished(QNetworkReply*) method. When this happens, it's safe for me to close compressedFile and to delete the data file represented by compressedFile. For debugging purposes I also added a few printf() statements to confirm that the transaction is complete:

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能够花费尽可能多的时间来传输我的文件。最后交易完成,我的postFinished()方法被调用。

Since compressedFile isn't closed immediately and doesn't go out of scope, the QNetworkAccessManager is able to take as much time as it likes to transmit my file. Eventually the transaction is complete and my postFinished() method gets called.

我的另一个问题(这也导致我看到交易从未完成的行为)是我的Web服务器的Python代码没有正确地部署POST,但这超出了我原来Qt问题的范围。

My other problem (which also contributed to the behavior I was seeing where the transaction never completed) was that the Python code for my web server wasn't fielding the POST correctly, but that's outside the scope of my original Qt question.

推荐答案

您正在堆栈上创建 compressedFile ,并将指针传递给您的QNetworkRequest(最终是您的QNetworkAccessManager)。一旦你离开你所在的方法, compressedFile 就会超出范围。虽然行为未定义,但我很惊讶它并没有让你崩溃。

You're creating compressedFile on the stack, and passing a pointer to it to your QNetworkRequest (and ultimately your QNetworkAccessManager). As soon as you leave the method you're in, compressedFile is going out of scope. I'm surprised it's not crashing on you, though the behavior is undefined.

您需要在堆上创建 QFile

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

您当然需要跟踪它然后删除一旦帖子完成,或者将其设置为 QNetworkReply 的子节点,以便在以后销毁时将其销毁:

You will of course need to keep track of it and then delete it once the post has completed, or set it as the child of the QNetworkReply so that it it gets destroyed when the reply gets destroyed later:

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

QNetworkReply *reply = netManager.post(QNetworkRequest(QUrl("http://mywebsite.com/upload") ), compressedFile); 
compressedFile->setParent(reply);

这篇关于使用QNetworkAccessManager的post()方法上传文件的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆