I'm using Qt's QNetworkAccessManager to download a file from a place (currently the local machine, but in the future it will be an HTTP server) and temporarily store it in the TEMP file (linux ubuntu). The problem I've found is that the file (which is an executable) gets corrupted in the process: when I try to run the file as executable, it returns a classical error of problematic cross-compilation.
Now that's interesting because the file is a executable for a Embedded Linux Device - I'm downloading the executable to my TEMP so I may send it later to the device. When that happens (using FileZilla), though, this error message appears:
./re8k_interface-tgt: line 1: syntax error: unexpected word (expecting ")")
Now I know the original file is fine by copying it to the device and running it, so I'm aware it has something to do with the process of copying the file, either when downloading or when writing to a QFile object. Here is how I'm doing it for now:
//Call to download
QUrl ulrTemp("//" + downloadUrls[downloadStep].arg(ui->sbID->text()));
ulrTemp.setScheme("file");
qDebug() << "Downloading from" << ulrTemp;
poReply = downloadNetworkManager->get(QNetworkRequest(ulrTemp));
connect(poReply,SIGNAL(downloadProgress(qint64,qint64)),this,SLOT(slotTransferProgress(qint64,qint64)));
connect(poReply,SIGNAL(error(QNetworkReply::NetworkError)),this,SLOT(slotTransferError(QNetworkReply::NetworkError)));
//When finished
QByteArray downloadedData;
downloadedData = reply->readAll();
reply->deleteLater();
poReply->deleteLater();
static const QString tempFilePath = QDir::tempPath();
QFile file(tempFilePath + "/" + downloadNames[downloadStep]);
if (!file.open(QFile::WriteOnly | QFile::Truncate))
{
qDebug() << "Failure opening temp file to write: " << file.fileName();
return;
}
QDataStream stream(&file);
stream << downloadedData;
file.close();
P.s.: I'm aware of the necessity of setting permissions
The copied file size matches exactly the original. So, where is the problem I can't see?
When writing a byte array to a QDataStream
, the array's length is written as well.
Simply don't use the data stream, use QFile
, or, better QTemporaryFile
directly.
The example below demonstrates how to leverage C++11 and Qt 5 to make it really simple:
Writing to: /var/folders/yy/2tl/T/download-29543601.L91178
Wrote 55015 bytes.
Downloaded 55015 of -1 bytes
Wrote 7572 bytes.
Wrote 6686 bytes.
Wrote 5104 bytes.
Downloaded 74377 of 74377 bytes
Successfully wrote /var/folders/yy/2tl/T/download-29543601.L91178
#include <QCoreApplication>
#include <QNetworkAccessManager>
#include <QNetworkReply>
#include <QTemporaryFile>
#include <QUrl>
#include <QByteArray>
#include <QTextStream>
#include <QDebug>
#include <cstdio>
QTextStream out(stdout);
QTextStream in(stdin);
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
QNetworkAccessManager mgr;
auto url = QUrl("http://stackoverflow.com/questions/29543601/"
"executable-getting-somehow-corrupted-when-being-copied");
auto reply = mgr.get(QNetworkRequest(url));
QTemporaryFile file;
if (!file.open()) {
qDebug() << "Can't open file for writing.";
return -1;
}
out << "Writing to: " << file.fileName() << endl;
QObject::connect(reply, &QNetworkReply::downloadProgress, [](qint64 rx, qint64 total) {
qDebug() << "Downloaded" << rx << "of" << total << "bytes";
});
QObject::connect(reply, &QIODevice::readyRead, [reply, &file]{
auto data = reply->readAll();
auto written = file.write(data);
if (data.size() != written) {
qDebug() << "Write failed, wrote" << written << "out of" << data.size() << "bytes.";
} else {
qDebug() << "Wrote " << written << "bytes.";
}
});
QObject::connect(reply, &QNetworkReply::finished, [reply, &file]{
if (reply->error() != QNetworkReply::NoError) {
qDebug() << "The request was unsuccessful. Error:" << reply->error();
qApp->quit();
return;
}
if (file.flush()) {
out << "Successfully wrote " << file.fileName();
out << "\nPress Enter to remove the file and exit." << flush;
in.readLine();
} else {
qDebug() << "The file flush has failed";
}
qApp->quit();
});
return a.exec();
}