c++qtqt5qdatastream

How to Save/Load a custom struct into a binary file using QDataStream in Qt?


I am going to save a struct in a binary file and load it later on. I found that one way is to use QVariant. Here is a simplified Qt Widget Application example that I have created. But when I run it the binary file remains empty. Could you please help me with that. Also, Is there a better method to do such a thing?

mainwindow.h:

#ifndef MAINWINDOW_H
#define MAINWINDOW_H

#include <QMainWindow>
#include <QFile>
#include <QFileDialog>
#include <QDataStream>
#include <QString>

#include "mystruct.h"

namespace Ui {
class MainWindow;
}

class MainWindow : public QMainWindow
{
    Q_OBJECT

public:
    explicit MainWindow(QWidget *parent = nullptr);
    ~MainWindow();

private:
    Ui::MainWindow *ui;
};
#endif

mainwindow.cpp:

#include "mainwindow.h"
#include "ui_mainwindow.h"

MainWindow::MainWindow(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::MainWindow)
{
    ui->setupUi(this);

    /* create an object of the struct */
    myStruct * aStruct = new myStruct;
    aStruct->myStringVar = QString("aaaaa");

    /* put the object in QVariant */
    QVariant aVariant;
    aVariant.setValue(aStruct);

    /* save the QVariant to binary file */
    QFile myFile("myFile");
    QDataStream save(&myFile);
    save.setVersion(QDataStream::Qt_4_6);
    save << aVariant;
    myFile.close();

    /* load the QVariant from binary file */
    QDataStream load(&myFile);
    load.setVersion(QDataStream::Qt_4_6);
    QVariant theVariant;
    load >> theVariant;
    QString theVar = theVariant.value<myStruct*>()->myStringVar;
    myFile.close();
}

MainWindow::~MainWindow()
{
    delete ui;
}

mystruct.h:

#ifndef MYSTRUCT_H
#define MYSTRUCT_H

#include <QMetaType>
#include <QString>

struct myStruct
{
    QString myStringVar;
};

Q_DECLARE_METATYPE(myStruct*)

#endif // MYSTRUCT_H

Comment: As a reference, this link shows a similar problem, but I could not understand/implement the suggestions correctly. For example, I tried to define a new operator, as it is explained here, but it did not work.


Solution

  • First of all you should not save the pointer since this is only the memory address of the variable, what should be saved is the value. On the other hand if you want to use QDataStream you must overwrite stream operators, finally if you want to save as QVariant you must use qRegisterMetaTypeStreamOperators. In addition to the above, your code has several errors such as not opening the QFile.

    mystruct.h

    #ifndef MYSTRUCT_H
    #define MYSTRUCT_H
    
    #include <QString>
    #include <QMetaType>
    
    struct myStruct
    {
        QString myStringVar;
        bool operator==(const myStruct & o){
            return o.myStringVar == this->myStringVar;
        }
        friend QDataStream &operator<<(QDataStream &out, const myStruct &rhs){
            out << rhs.myStringVar;
            return out;
        }
        friend QDataStream &operator>>(QDataStream &in, myStruct &rhs){
            in >> rhs.myStringVar;
            return in;
        }
    };
    Q_DECLARE_METATYPE(myStruct)
    
    #endif // MYSTRUCT_H
    

    main.cpp

    #include "mystruct.h"
    
    #include <QDataStream>
    #include <QFile>
    #include <QVariant>
    
    int main(int argc, char *argv[])
    {
        qRegisterMetaTypeStreamOperators<myStruct>("myStruct");
    
        // create struct
        myStruct aStructIn{"aaa"};
    
        // myStruct to QVariant
        QVariant aVariant;
        aVariant.setValue(aStructIn);
    
        //open file
        QFile myFile("myFile");
        if(!myFile.open(QIODevice::WriteOnly))
            return -1;
    
        // save QVariant
        QDataStream save(&myFile);
        save.setVersion(QDataStream::Qt_4_6);
        save << aVariant;
        myFile.close();
    
        //open file
        if(!myFile.open(QIODevice::ReadOnly))
            return -1;
    
        // read QVariant
        QDataStream load(&myFile);
        load.setVersion(QDataStream::Qt_4_6);
        QVariant theVariant;
        load >> theVariant;
        myFile.close();
    
        // QVariant to myStruct
        myStruct aStructOut = theVariant.value<myStruct>();
    
        Q_ASSERT(aStructOut == aStructIn);
    
        return 0;
    }