我正在與一個團隊進行 Qt 專案。我有兩個函式——一個檢索地點的數字坐標,另一個下載地點的地圖——我想將它們合并到一個包裝類中,以便我的隊友可以輕松呼叫它。
#include <QCoreApplication>
#include <QFile>
#include <QHttpMultiPart>
#include <QNetworkAccessManager>
#include <QNetworkReply>
#include <iostream>
class OpenStreetMapWrapper: public QObject{
Q_OBJECT
public:
OpenStreetMapWrapper(QObject *parent=nullptr):QObject(parent){
connect(&manager, &QNetworkAccessManager::finished, this, &OpenStreetMapWrapper::handle_finished);
}
void download(const std::string ®ion, const std::string &department, const QFile& outfile){
QNetworkRequest request;
QUrl url = QUrl(QString::fromStdString("https://download.openstreetmap.fr/extracts/europe/france/" region "/" department ".osm.pbf"));
request.setUrl(url);
request.setAttribute(QNetworkRequest::User, outfile.fileName());
manager.get(request);
}
void searchCSV(QFile& file, QFile& outfile){
QNetworkRequest request(QUrl("https://api-adresse.data.gouv.fr/search/csv/")); // Free API provided by the French government
request.setAttribute(QNetworkRequest::User, outfile.fileName());
QHttpMultiPart *multipart = new QHttpMultiPart(QHttpMultiPart::FormDataType);
QHttpPart postpart;
postpart.setHeader(QNetworkRequest::ContentDispositionHeader,
QString("form-data; name=%1; filename=%2")
.arg("data", file.fileName()));
postpart.setBodyDevice(&file);
multipart->append(postpart);
file.setParent(multipart);
manager.post(request, multipart);
}
private:
QNetworkAccessManager manager;
void handle_finished(QNetworkReply *reply){
if(reply->error() == QNetworkReply::NoError){
QByteArray read = reply->readAll();
std::cout << read.toStdString() << std::endl; // For debugging
QString filename = reply->request().attribute(QNetworkRequest::User).toString();
QFile out(filename);
if(out.open(QIODevice::WriteOnly)){
out.write(read);
out.close();
}
}
else{
qDebug() << reply->error() << reply->errorString();
}
reply->deleteLater();
// QCoreApplication::quit(); This is done somewhere else?
}
};
#include <main.moc>
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
OpenStreetMapWrapper A;
QFile file("./search.csv");
file.open(QIODevice::ReadWrite);
QFile outfile("./output.csv");
outfile.open(QIODevice::ReadWrite);
// Search
A.searchCSV(file, outfile); // 1st call works
A.searchCSV(file, outfile); // 2nd call -> makes both calls fail.
// Downloader
std::string region = "corse";
std::string department = "haute_corse";
return a.exec();
}
上面代碼的問題在于,例如當呼叫 searchCSV 時,它會根據需要顯示輸出,但如果在代碼中呼叫兩次,則根本沒有輸出。經過一些除錯,我認為問題是manager和handle_finished沒有正確連接,因為執行永遠不會到達那里。有沒有簡單的方法來解決這個問題?理想情況下,只有一個類 Instant,任??何方法都可以被呼叫任意次。
uj5u.com熱心網友回復:
我不太了解Qt,但看起來您正在嘗試讀取file兩次,我的猜測是當它在第一次呼叫A.searchCSV完成后到達檔案末尾時,您無法再讀取它- 除非您將 重新定位QFile到檔案的開頭。
可能的解決方案:
A.searchCSV(file, outfile);
file.unsetError(); // possibly needed
file.seek(0); // rewind to the start of the file
A.searchCSV(file, outfile);
uj5u.com熱心網友回復:
兩個 QFile(輸入、輸出)在兩個異步呼叫 (searchCSV) 之間共享,這可能會產生未定義的行為。輸入檔案(流)內容只有在建立連接后才會被加載和推送(就像 curl 那樣)。
你應該:
- 使 searchCSV 成為阻塞函式(等到 handle_finished() 完成),輸入檔案指標應在其他呼叫之前重新初始化。
- 或:使用分離的輸入/輸出 QFile 實體
轉載請註明出處,本文鏈接:https://www.uj5u.com/caozuo/359384.html
