使用 QNetworkAccessManager 的 post() 方法上传文件

2024-02-17

我在使用 Qt 应用程序时遇到一些问题;特别是 QNetworkAccessManager 类。我正在尝试使用 QNetworkAccessManager 的 post() 方法执行二进制文件的简单 HTTP 上传。文档指出我可以为 post() 提供一个指向 QIODevice 的指针,并且该类将传输在 QIODevice 中找到的数据。这表明我应该能够为 post() 提供一个指向 QFile 的指针。例如:

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

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

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

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

  1. QFile 在 Windows 下的工作方式是否存在某种限制?
  2. 我是否应该使用 QFile 或 QNetworkAccessManager 通过 post() 推送文件?
  3. 这根本不起作用吗?我是否必须找到其他方法来上传我的文件?

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

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

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

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

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

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

来自 QNetworkAccessManager 的 finish(QNetworkReply*) 信号触发我的 postFinished(QNetworkReply*) 方法。发生这种情况时,我可以安全地关闭compressedFile并删除co​​mpressedFile表示的数据文件。出于调试目的,我还添加了一些 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能够花费尽可能多的时间来传输我的文件。最终交易完成并且我的 postFinished() 方法被调用。

我的另一个问题(这也导致了我所看到的事务从未完成的行为)是我的 Web 服务器的 Python 代码没有正确处理 POST,但这超出了我最初的 Qt 问题的范围。


你正在创造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);
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

使用 QNetworkAccessManager 的 post() 方法上传文件 的相关文章

随机推荐