windows 使用 QNetworkAccessManager 的 post() 方法上传文件
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/2806274/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Uploading a file using post() method of QNetworkAccessManager
提问by dbisdorf
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:
我在使用 Qt 应用程序时遇到了一些问题;特别是 QNetworkAccessManager 类。我正在尝试使用 QNetworkAccessManager 的 post() 方法对二进制文件执行简单的 HTTP 上传。文档指出我可以将指向 QIODevice 的指针提供给 post(),并且该类将传输在 QIODevice 中找到的数据。这向我表明我应该能够给 post() 一个指向 QFile 的指针。例如:
QFile compressedFile("temp");
compressedFile.open(QIODevice::ReadOnly);
netManager.post(QNetworkRequest(QUrl("http://mywebsite.com/upload") ), &compressedFile);
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.
在我开发的 Windows 系统上似乎发生的事情是我的 Qt 应用程序从 QFile 推送数据,但随后没有完成请求;它似乎坐在那里等待更多数据从文件中显示出来。在我手动终止应用程序之前,发布请求不会“关闭”,此时整个文件显示在我的服务器端。
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.
从一些调试和研究来看,我认为这是因为 QFile 的 read() 操作在到达文件末尾时不会返回 -1。我认为 QNetworkAccessManager 正在尝试从 QIODevice 读取,直到它从 read() 获得 -1,此时它假定没有更多数据并关闭请求。如果它不断从 read() 获得零返回码,QNetworkAccessManager 假设可能有更多数据到来,因此它一直在等待那个假设数据。
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:
我已经通过一些测试代码确认 QFile 的 read() 操作在您读取到文件末尾后仅返回零。这似乎与 QNetworkAccessManager 的 post() 方法期望 QIODevice 的行为方式不兼容。我的问题是:
- Is this some sort of limitation with the way that QFile works under Windows?
- Is there some other way I should be using either QFile or QNetworkAccessManager to push a file via post()?
- Is this not going to work at all, and will I have to find some other way to upload my file?
- QFile 在 Windows 下的工作方式是否存在某种限制?
- 是否有其他方法我应该使用 QFile 或 QNetworkAccessManager 通过 post() 推送文件?
- 这根本行不通吗,我是否必须找到其他方法来上传我的文件?
Any suggestions or hints would be appreciated.
任何建议或提示将不胜感激。
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.
更新:事实证明我有两个不同的问题:一个在客户端,一个在服务器端。在客户端,我必须确保我的 QFile 对象在网络事务期间保持不变。QNetworkAccessManager 的 post() 方法立即返回但实际上并未立即完成。您需要在 QNetworkAccessManager 的 finished() 信号上附加一个插槽,以确定 POST 何时实际完成。在我的情况下,很容易或多或少地永久保留 QFile,但我还附加了一个插槽到完成()信号以检查来自服务器的错误响应。
I attached the signal to the slot like this:
我将信号附加到插槽,如下所示:
connect(&netManager, SIGNAL(finished(QNetworkReply*) ), this, SLOT(postFinished(QNetworkReply*) ) );
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 是我的类的成员,因此在此代码之后不会超出范围):
compressedFile.open(QIODevice::ReadOnly);
netManager.post(QNetworkRequest(QUrl(httpDestination.getCString() ) ), &compressedFile);
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:
来自 QNetworkAccessManager 的 finished(QNetworkReply*) 信号触发了我的 postFinished(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();
}
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.
由于compressedFile 不会立即关闭并且不会超出范围,因此QNetworkAccessManager 能够花费尽可能多的时间来传输我的文件。最终交易完成,我的 postFinished() 方法被调用。
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.
我的另一个问题(这也导致了我看到交易从未完成的行为)是我的 Web 服务器的 Python 代码没有正确填写 POST,但这超出了我最初的 Qt 问题的范围。
回答by Brian Roach
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.
您正在compressedFile
堆栈上创建,并将指向它的指针传递给您的 QNetworkRequest(最终是您的 QNetworkAccessManager)。一旦你离开你所在的方法,compressedFile
就会超出范围。尽管行为未定义,但我很惊讶它并没有让你崩溃。
You need to create the QFile
on the heap:
您需要QFile
在堆上创建:
QFile *compressedFile = new QFile("temp");
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:
您当然需要跟踪它,然后delete
在帖子完成后跟踪它,或者将其设置为 the 的子项,QNetworkReply
以便在稍后回复销毁时将其销毁:
QFile *compressedFile = new QFile("temp");
compressedFile->open(QIODevice::ReadOnly);
QNetworkReply *reply = netManager.post(QNetworkRequest(QUrl("http://mywebsite.com/upload") ), compressedFile);
compressedFile->setParent(reply);
回答by Xavier Decoret
You can also schedule automatic deletion of a heap-allocated file using signals/slots
您还可以使用信号/插槽安排自动删除堆分配的文件
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, it is much more localized and encapsulated than having to keep around your file in the outer class.
恕我直言,与必须在外部类中保留文件相比,它更加本地化和封装。
Note that you must remove the first connect()
if you have your postFinished(QNetworkReply*)
slot, in which you must then not forget to call reply->deleteLater()
inside it for the above to work.
请注意,connect()
如果您有postFinished(QNetworkReply*)
插槽,则必须删除第一个,然后不要忘记在其中调用reply->deleteLater()
它以使上述工作正常进行。