Qt getting network requests with QNetworkReply that download data to temp file - c++

I am having some issues reading an online file. I'm trying to read what is in the file after it gets downloaded to a temporary file. Here is my code:
void MainWindow::fileIsReady( QNetworkReply * reply)
{
QTemporaryFile tmpFile;
tmpFile.write(reply->readAll());
QByteArray asdf = reply->readAll();
qDebug() (QString("%1").arg(asdf.length())); // returns 0
if (tmpFile.open())
{
qDebug << "attempting to read file";
QTextStream stream(&tmpFile);
QString value = stream.readAll();
qDebug << value; // value is returning nothing
}
else
{
qDebug() << "failed to open internet file";
}
}
// in MainWindow constructor (MainWindow::MainWindow)...
QNetworkAccessManager * manager = new QNetworkAccessManager(this);
connect(manager, SIGNAL(finished(QNetworkReply*)), this, SLOT(fileIsReady(QNetworkReply*)) );
manager->get(QNetworkRequest(QUrl("https://www.website.com/stuff/file.exe.md5")));
I'm going to be using this to compare two md5 strings.

There are several issues in your code:
You need to open tmpFile before writing to it.
reply->readAll() will return data only once. Further calls will return empty array. Once you received data using readAll, it's your responsibility to store it in a variable if you need it later.
After you wrote someting to file, the file pointer is at its end. You cannot read anything from it because there is no data there. You can use seek to move pointer to the beginning of the file and read its content.
There is no point in reading from file just after you wrote data to it. You can use QTextStream on QNetworkReply directly to read text from it. (Maybe this was just for debugging, I don't know.)
It's hard to believe that you need to create a temporary file just to calculate md5. There are simplier ways to do that.

So turns out I was dumb and forgot to open the reply first. Also, it was unnecessary for me to create a temp file. Here is my solution::
void MainWindow::fileIsReady( QNetworkReply * reply)
{
if (reply->error() == QNetworkReply::NoError)
{
if (reply->open(QIODevice::ReadOnly))
{
QByteArray asdf = reply->readAll();
qDebug() << (QString("asdf %1").arg(asdf.length()));
qDebug() << (QString(asdf));
}
else
{
qDebug << "cant open reply";
}
}
}

Related

Converting valid QFile to QString - QString is empty

So I am trying to convert a QFile into a QString by doing the following:
void MainWindow::openTemplateFile(QString location)
{
if (location.isEmpty())
return;
else
{
QString variable;
templateFile.setFileName(location);
if (!templateFile.open(QFile::ReadOnly | QFile::Text))
{
QMessageBox::information(this, "Unable to open template",
templateFile.errorString());
return;
}
else // file opened and ready to read from
{
QTextStream in(&templateFile);
QString fileText = in.readAll();
qDebug() << templateFile.size() << in.readAll();
}
}
}
However, in I get the following result in the debug console:
48 ""
templateFile does exist and is part of the MainWindow class. This is also simplified code - in the actual program I read chars from the file and it works correctly. The location string is a result of the QFileDialog::getOpenFileName function, which I open a txt file with.
You call readAll() twice. The second time, the stream is positioned at end-of-file, and so readAll() has nothing to read and returns an empty string. Print fileText in your debug output instead.

How can i write the serial port incoming data into text file (.txt)

How I can write the serial port incoming data into text file(.txt).. The data write should have one hour interval time.
Following this the serial read data code:
void MainWindow::readData()
{
QByteArray data = serial->readAll();
QDataStream stream(data);
double value;
stream>>value;
console->putData(data);
qDebug()<<value;
}
I have tried this way but failed
void Write(QString Filename)
{
QFile mFile(Filename);
if(!mFile.open(QFile::WriteOnly | QFile::Text))
{
qDebug() << "Could not open file for writing";
return;
}
QTextStream out(&mFile);
out << data;
mFile.flush();
mFile.close();
}
I suggest you to use QByteArray for receiving and use signal readyRead() to call receive function when data is received.
QSerialPort *serialPort= new QSerialPort();
connect(serialPort, &QSerialPort::readyRead, this, &MainWindow::receiveData_WriteToFile);
This function read data and write it in file.
void MainWindow::receiveData_WriteToFile()
{
if (serialPort->isOpen())
{
QByteArray DataReceived;
QFile LogFile("D:/data.txt");
if(!LogFile.open(QFile::Append | QFile::Text))
{
//Can't Open Log File.
}
if(serialPort->bytesAvailable())
{
DataReceived = serialPort->readAll();//All Data Received Successfully.
if(DataReceived.size() > 0)
{
if(LogFile.isOpen())
{
QTextStream in(&LogFile);
in << DataReceived;
}
LogFile.close();
}
else
{
//Fail To Receive Data.
}
}
LogFile.close();
}
}
readyRead() : This signal is emitted once every time new data is available for reading from the device's current read channel. It will only be emitted again once new data is available, such as when a new payload of network data has arrived on your network socket, or when a new block of data has been appended to your device.
output file:
This is a sample project for your question on github download here.

QDataStream unable to serialize data

I am trying to follow the tutorial here and serialize Qt objects. Here is my code:
QFile file("/Users/kaustav/Desktop/boo.dat");
if (!file.open(QIODevice::WriteOnly)) {
qDebug() << "Cannot open file for writing: "
<< qPrintable(file.errorString()) << endl; //no error message gets printed
return 0;
}
QDataStream out(&file); // we will serialize the data into the file
out.setVersion(QDataStream::Qt_5_3); //adding this makes no difference
out << QString("the answer is"); // serialize a string
out << (qint32)42;
When I run this program, the file gets created in my desktop all right, but its size is 0 kB, it is blank. Naturally, when I then try this:
QFile file("/Users/kaustav/Desktop/boo.dat");
file.open(QIODevice::ReadOnly);
QDataStream in(&file); // read the data serialized from the file
in.setVersion(QDataStream::Qt_5_3);
QString str;
qint32 w;
in >> str >> w;
I get a blank string in str. What am I doing wrong? If of any help, I am using Qt Creator 3.1.1 based on Qt 5.2.1.
Check if there are any errors returned when calling open and ensure you close the file with file.close() when you're finished with it.
As you're using Qt 5, you should really use QSaveFile instead, when saving the data.

Outputting QProcess readAll response to label

I have a QProcess where i would like to output the response in a label. First off, here is what i have tried:
QProcess *proc = new QProcess();
proc->setProcessChannelMode(QProcess::MergedChannels);
proc->start(cmdLineRequest.toUtf8().constData()); // cmdLineRequest is omitted
if (!proc->waitForFinished()) {
qDebug() << "Make failed:" << proc->errorString();
ui->topBarcode->setText(QString(proc->errorString()));
} else {
qDebug() << "Make output:" << proc->readAll();
ui->topBarcode->setText(QString(proc->readAll()) + "asdf");
}
proc->readAll() is a QByteArray and setText accepts a QString. From what i've read, i should be able to cast the QByteArray to a QString, howver it does not work. I have also tried to convert proc->readAll() with the QString class
->setText(QString::fromUtf8(proc->readAll())) // not working
->setText(QString::fromLatin1(proc->readAll())) // not working
->setText(QString::fromLocal8Bit(proc->readAll())) // not working
... etc ...
It seems weird, since i'm adding pictures to labels in nearly the same matter using setPixmap(QPixmap::fromImage(image))
Any help appreciated, thank you.
Update:
If i add a QMessageBox before the end of the method that the above block of code belongs to, i can see the text added to the label. However when i close the QMessageBox, the text dissapears. Am i giving an address position to the label with proc->readAll() or how come this behaviour? Thank you.
The problem here is that you're calling proc->readAll twice; the first for the qDebug output and then again for the string which you set on the label.
{
qDebug() << "Make output:" << proc->readAll();
ui->topBarcode->setText(QString(proc->readAll()) + "asdf");
}
I expect that as QProcess is a QIODevice, it's returning a buffered byte array. When you read it, it removes that from the buffer.
Therefore, create a temporary string and read the buffer once, before calling qDebug and setting the string to the label: -
{
QString output = proc->readAll();
qDebug() << "Make output:" << output;
ui->topBarcode->setText(output + "asdf");
}
You should listen to readyReadStandardOutput() signal and call readAll() when you receive signal.
or you can call
bool waitForReadyRead(int msecs = 30000)
before calling readAll().

QNetworkAccessManager multiple uploads fail

In my App, I have a method to upload files to the server, this works fine.
But when I call this method multiple times at once (like iterating over the result of a chooseFilesDialog) the first 7 (more or less) files are uploaded correctly, the others never get uploaded.
I think this has to be linked with the fact the server doesn't allow more than X connections from the same source maybe?
How can I make sure the upload waits for a free, established connection?
this is my method:
QString Api::FTPUpload(QString origin, QString destination)
{
qint64 timestamp = QDateTime::currentMSecsSinceEpoch();
QUrl url("ftp://ftp."+getLSPro("domain")+destination);
url.setUserName(getLSPro("user"));
url.setPassword(getLSPro("pwd"));
QFile *data = new QFile(origin, this);
if (data->open(QIODevice::ReadOnly))
{
QNetworkAccessManager *nam = new QNetworkAccessManager();
QNetworkReply *reply = nam->put(QNetworkRequest(url), data);
reply->setObjectName(QString::number(timestamp));
connect(reply, SIGNAL(uploadProgress(qint64, qint64)), SLOT(uploadProgress(qint64, qint64)));
return QString::number(timestamp);
}
else
{
qDebug() << "Could not open file to FTP";
return 0;
}
}
void Api::uploadProgress(qint64 done, qint64 total) {
QNetworkReply *reply = (QNetworkReply*)sender();
emit broadCast("uploadProgress","{\"ref\":\""+reply->objectName()+"\" , \"done\":\""+QString::number(done)+"\", \"total\":\""+QString::number(total)+"\"}");
}
First, don't create a QNetworkManager every time you start an upload.
Second, you definitely have to delete everything you new(), otherwise you are left with memory leaks. This includes the QFile, the QNetworkManager AND the QNetworkReply (!).
Third, you have to wait for the finished() signal.
Api::Api() { //in the constructor create the network access manager
nam = new QNetworkAccessManager()
QObject::connect(nam, SIGNAL(finished(QNetworkReply*)), this, SLOT(finished(QNetworkReply*)));
}
Api::~Api() { //in the destructor delete the allocated object
delete nam;
}
bool Api::ftpUpload(QString origin, QString destination) {
qint64 timestamp = QDateTime::currentMSecsSinceEpoch();
QUrl url("ftp://ftp."+getLSPro("domain")+destination);
url.setUserName(getLSPro("user"));
url.setPassword(getLSPro("pwd"));
//no allocation of the file object;
//will automatically be destroyed when going out of scope
//I use readAll() (see further) to fetch the data
//this is OK, as long as the files are not too big
//If they are, you should allocate the QFile object
//and destroy it when the request is finished
//So, you would need to implement some bookkeeping,
//which I left out here for simplicity
QFile file(origin);
if (file.open(QIODevice::ReadOnly)) {
QByteArray data = file.readAll(); //Okay, if your files are not too big
nam->put(QNetworkRequest(url), data);
return true;
//the finished() signal will be emitted when this request is finished
//now you can go on, and start another request
}
else {
return false;
}
}
void Api::finished(QNetworkReply *reply) {
reply->deleteLater(); //important!!!!
}