Serializing QHash to QByteArray - qt

I am trying to serialize a QHash object and store it in a QByteArray (to be sent using QUDPSocket or QTCPSocket).
My current attempt looks like this:
// main.cpp
#include <QtCore/QCoreApplication>
#include <QHash>
#include <QVariant>
#include <QDebug>
int main(int argc, char *argv[])
{
QHash<QString,QVariant> hash;
hash.insert("Key1",1);
hash.insert("Key2","thing2");
QByteArray ba;
QDataStream ds(&ba, QIODevice::WriteOnly);
ds << hash;
qDebug() << ds;
}
When this runs I get this out of qDebug():
QIODevice::read: WriteOnly device
QIODevice::read: WriteOnly device
QIODevice::read: WriteOnly device
QVariant(, )
The documentation says that this should write to the byte array, but obviously that isn't happening here. What am I doing wrong?
Qt 4.7.1 on OS-X
Thanks!
-J

The reason it is failing is because it is trying to read from a write-only stream. The sequence is:
qDebug() << ds;
--> QVariant::QVariant(QDataStream &s)
--> QDataStream& operator>>(QDataStream &s, QVariant &p)
--> void QVariant::load(QDataStream &s)
That last method (and some more downstream) try to read from the data stream to convert its contents into a QVariant for display in qDebug. In other words, your actual code is fine; the debugging check is causing the failure.
You could check the contents of the byte array with something like:
qDebug() << ba.length() << ba.toHex();

You can Implement you program like this code:
QHash<QString,QVariant> options;
options["string"] = "my string";
options["bool"] = true;
QByteArray ar;
//Serializing
QDataStream out(&ar,QIODevice::WriteOnly); // write the data
out << options;
//setting a new value
options["string"] = "new string";
//Deserializing
// read the data serialized from the file
QDataStream in(&ar,QIODevice::ReadOnly);
in >> options;
qDebug() << "value: " << options.value("string");
ref

Related

Save and load QWebEngineHistory to a QWebEnginePage

I need to save the history of a QWebEnginePage and load it back. Therefore I want to store the history from page A in some structure and set it to page B.
In the documentation I found the following methods:
// Saves the web engine history history into stream.
QDataStream &operator<<(QDataStream &stream, const QWebEngineHistory &history)
// Loads the web engine history from stream into history.
QDataStream &operator>>(QDataStream &stream, QWebEngineHistory &history)
But honestly I don't know how to work with them.
I tried the following:
QWebEnginePage *m_history;
...
...
void setHistory(QWebEngineHistory *history){
QDataStream data;
data << history; //Hoping that the content of data is persistent after deleting of the QWebEnginePage where the history is coming from
data >> m_history;
}
And later on I want to load it back to the page:
m_history >> m_webEnginePage.history(); // Pseudo-Code
I know that the QWebEngineHistory of a QWebEnginePage is const, but then I'm wondering why are there even those two methods from above? Why is there a function that "loads the web engine history into history"?
The only alternative I can think of is storing my history in a QList, but managing this is not nice and could lead to more problems (because of the whole forward/backward button etc).
Thank you very much for your help.
No object can be saved, what is saved is the information associated with the object so you should not create QWebEngineHistory but save and/or load the information.
In the following example, the information is saved in a file when the application is closed and the startup is loaded.
#include <QtWebEngineWidgets>
int main(int argc, char *argv[]) {
QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
QApplication app(argc,argv);
const QString filename = "history.bin";
QWebEngineView view;
view.load(QUrl("https://stackoverflow.com"));
{// load
QFile file(filename);
if(file.open(QFile::ReadOnly)){
qDebug() << "load";
QDataStream ds(&file);
ds >> *(view.page()->history());
}
}
view.resize(640, 480);
view.show();
int ret = app.exec();
{// save
QFile file(filename);
if(file.open(QFile::WriteOnly)){
qDebug() << "save";
QDataStream ds(&file);
ds << *(view.page()->history());
}
}
return ret;
}
In the same way you can save it through QSettings:
#include <QtWebEngineWidgets>
int main(int argc, char *argv[]) {
QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
QApplication app(argc,argv);
QWebEngineView view;
view.load(QUrl("https://stackoverflow.com"));
{// load
QSettings settings;
QByteArray ba = settings.value("page/history").toByteArray();
QDataStream ds(&ba, QIODevice::ReadOnly);
ds >> *(view.page()->history());
}
view.resize(640, 480);
view.show();
int ret = app.exec();
{// save
QSettings settings;
QByteArray ba;
QDataStream ds(&ba, QIODevice::WriteOnly);
ds << *(view.page()->history());
settings.setValue("page/history", ba);
}
return ret;
}

QNetworkManager uploading file to FTP crash

I am trying to upload a simple test text file to a FTP server. In order to achieve this I am using QNetworkAccessManager, since QFtp has been deprecated in Qt 5.1.
I created a test.txt file in the programs directory and using QFile I am opening it as QIODevice::ReadWrite | QIODevice::Text.
The problem is when I set the connection and tell the QNetworkAccessManager to upload a file the program crashes ("FTPConnectionTest does not respond"). It happens both when I am trying to use an external FTP server or a local one created with FileZilla.
I connected all signals emitted by the reply (functions: uploadFinish, uploadProgress, uploadError) however no feedback is beeing captured.
Question: Is this problem lying on the side of FTP server or am I doing something wrong in my code?
Code snipped below:
Main.cpp
#include <QCoreApplication>
#include <ftp.h>
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
Ftp ftp;
return a.exec();
}
ftp.cpp
#include "ftp.h"
#include <QtNetwork/QNetworkAccessManager>
#include <QtNetwork/QNetworkReply>
#include <QtNetwork/QNetworkRequest>
#include <QFile>
#include <QUrl>
#include <QDebug>
Ftp::Ftp()
{
QFile file("test.txt");
if (file.open(QIODevice::ReadWrite | QIODevice::Text)) {
url = QUrl("ftp://127.0.0.1/test.txt");
url.setUserName("user");
url.setPassword("password");
qDebug() << "URL set" << url;
QNetworkAccessManager* nam = new QNetworkAccessManager();
qDebug() << "nam set";
QNetworkReply *rep = nam->put(QNetworkRequest(url), &file);
qDebug() << "after rep";
connect(rep, SIGNAL(finished()), this, SLOT(uploadFinish()));
connect(rep, SIGNAL(error(QNetworkReply::NetworkError)), this, SLOT(uploadError(QNetworkReply::NetworkError)));
connect(rep, SIGNAL(downloadProgress(qint64,qint64)), this, SLOT(uploadProgress(qint64,qint64)));
}
else qDebug() << "failed to open";
}
void Ftp::uploadFinish()
{
qDebug() << "finished uploading file";
}
void Ftp::uploadProgress(qint64 a, qint64 b)
{
qDebug() << a << "/" << b;
}
void Ftp::uploadError(QNetworkReply::NetworkError state)
{
qDebug() << "State" << state;
}
See the QNetworkAccessManager::put documentation:
data must be opened for reading when this function is called and must remain valid until the finished() signal is emitted for this reply.
Your file object falls out of scope when the constructor finishes execution, so QNetworkAccessManager probably tries to read from object that is already deleted. You need to make file a class member variable or create it using QFile* file = new QFile().

QFile doesn’t create the file

I am writing a simple program. The program has 2 QStrings set with following variables: path and name of file, there is a 3rd QString which I later on use to put the result of the append of the first 2 QString together in. What I want to do is append the 2 QStrings and put them in the appendAll QString, and then send the appendAll QString to the QFile variable constructor. Now when I do that, it prints "Failed to Create File", this is the code I used:
#include <QString>
#include <QTextStream>
#include <QFile>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
QTextStream output(stdout);
QString location = "/home/mahmoud/Destkop";
QString name = "mahmoud.txt";
QString appendAll;
if( !location.endsWith("/") )
{
location.append("/");
}
appendAll = location.append(name);
output << appendAll << endl;
QFile myFile(appendAll);
if(myFile.open(QIODevice::WriteOnly | QIODevice::Text ))
{
output << "File Has Been Created" << endl;
}
else
{
output << "Failed to Create File" << endl;
}
QTextStream writeToFile(&myFile);
writeToFile << "Hello World" << endl;
myFile.close();
return a.exec();
}
But when I type the string directly into the QFile variable constructor in the same program it prints, "File Has Been Created" and I find it on my desktop, the below code works fine:
QFile myFile("/home/mahmoud/Desktop/mahmoud.txt");
if(myFile.open(QIODevice::WriteOnly | QIODevice::Text ))
{
output << "File Has Been Created" << endl;
}
else
{
output << "Failed to Create File" << endl;
}
I want to be able to already have QStrings and append them and send them to the QFile variable constructor, any suggestions on how to solve my problem? Thank You
Do not hard-code this filesystem location. Instead, in Qt4 you should be using QDesktopServices:
QString location =
QDesktopServices::storageLocation(QDesktopServices::DesktopLocation);
In Qt5, it's QStandardPaths:
QString location =
QStandardPaths::writableLocation(QStandardPaths::DesktopLocation);
This is important because /home/username/Desktop is not guaranteed to be the user's Desktop folder.
There is typing error in your code: Destkop should be Desktop. Qt can't create file in non-existent directory.

QT QString from QDataStream

I'm working with a buffer and I'm trying to get a string from it, but isnt working...
Example:
*void myFunc(QDataStream& in)
{
quint8 v;
in >> v;
// Ok, I caught v value successfuly
QString s;
in >> s;
// Didnt work :<
}*
The string lenght is stored on 2 first bytes...
Thanks
If the string was not written as a QString, you need to read its length and content separately.
quint8 v;
in >> v;
quint16 length = 0;
in >> length;
// the string is probably utf8 or latin
QByteArray buffer(length, Qt::Uninitialized);
in.readRawData(buffer.data(), length);
QString string(buffer);
You might have to change the endianness of the QDataStream with QDataStream::setByteOrder before reading the 16-bit length.
We should really see the writing code and how you create the QDataStream. I tried with the following sample, and in this case your function works very well:
#include <QCoreApplication>
#include <QDebug>
#include <QDataStream>
#include <QBuffer>
void myFunc(QDataStream& in)
{
quint8 v;
in >> v;
qDebug() << v;
// Ok, I caught v value successfuly
QString s;
in >> s;
qDebug() << s;
// Didnt work :<
}
int main(int argc, char ** argv) {
QCoreApplication a(argc, argv);
QBuffer buffer;
buffer.open(QBuffer::ReadWrite);
// write test data into the buffer
QDataStream out(&buffer);
quint8 ival = 42;
QString sval = "Qt";
out << ival;
out << sval;
// read back data
buffer.seek(0);
myFunc(out);
return a.exec();
}
Output when executed:
$ ./App
42
"Qt"

Qt Problems compiling using an extern variable

I have a rellly long process that produces about 700 Mb of a txt log output file. This is very hard to manage. So I want to divide the output in multiple smaller log files. This is what my main.cpp looks like
#include <QtGui/QApplication>
#include "mineedit.h"
#include "logoutput.h"
#include <iostream>
void messageHandling(QtMsgType type, const char *msg){
if (ERRORLOGGER.isEmpty()){
ERRORLOGGER = DEFERRORLOGGER;
}
std::cout << "In Message Handling" << std::endl;
std::cout << "Writing to file" << ERRORLOGGER.toStdString() << std::endl;
QFile file(ERRORLOGGER);
file.open(QFile::Append);
QTextStream stream(&file);
switch (type) {
case QtDebugMsg:
stream << msg << "\n";
file.close();
break;
case QtWarningMsg:
stream << "WARNING: " << msg << "\n";
file.close();
break;
case QtCriticalMsg:
stream << "CRITICAL: " << msg << "\n";
file.close();
break;
case QtFatalMsg:
stream << "FATAL: " << msg << "\n";
file.close();
abort();
}
}
int main(int argc, char *argv[])
{
ERRORLOGGER = DEFERRORLOGGER;
qInstallMsgHandler(messageHandling);
QApplication a(argc, argv);
MineEdit w;
w.show();
return a.exec();
}
[/CODE]
And my logoutput.h is like
#ifndef LOGOUTPUT_H
#define LOGOUTPUT_H
#include <QString>
//----------------------------For outputting an error file------------------------------
#define DEFERRORLOGGER "/home/aarelovich/Documents/log.err"
#define FOLDER_OUTPUT_LOG "./home/aarelovich/Documents"
extern QString ERRORLOGGER;
#endif // LOGOUTPUT_H
Now in a part of my code I do:
ERRORLOGGER = name_of_current_log_file.
However I get the following compilation errors:
obj/main.o: In function messageHandling(QtMsgType, char const*)':
/home/aarelovich/Dropbox/MineSim/main.cpp:8: undefined reference toERRORLOGGER'
/home/aarelovich/Dropbox/MineSim/main.cpp:9: undefined reference to ERRORLOGGER'
/home/aarelovich/Dropbox/MineSim/main.cpp:13: undefined reference toERRORLOGGER'
/home/aarelovich/Dropbox/MineSim/main.cpp:15: undefined reference to ERRORLOGGER'
obj/main.o: In functionmain':
/home/aarelovich/Dropbox/MineSim/main.cpp:40: undefined reference to ERRORLOGGER'
obj/mineedit.o:/home/aarelovich/Dropbox/MineSim/mineedit.cpp:101: more undefined references toERRORLOGGER' follow
collect2: ld returned 1 exit status
Can anyone please tell me what am I doing wrong? Or how I can dynamically change the output file in which I create my application log?
Thanks for any help
Your problem is probably related to extern variable.
Here is an example of how to use extern keyword in c++.
Beware that C++ and C have differences with extern keyword when linking.
Basicall what you need to do is
global.cpp:
// declaration of g_nValue
int g_nValue = 5;
main.cpp:
// extern tells the compiler this variable is declared elsewhere
extern int g_nValue;
int main()
{
g_nValue = 7;
return 0;
}
In your example if you use extern QString ERRORLOGGER; in logoutput.h,
this variable needs to be declared in another cpp just as explained in the link.
I hope this helps

Resources