Как сохранить / загрузить пользовательскую структуру в двоичный файл, используя QDataStream в Qt? - PullRequest
0 голосов
/ 13 сентября 2018

Я собираюсь сохранить структуру в двоичном файле и загрузить ее позже.Я обнаружил, что одним из способов является использование QVariant.Вот упрощенный пример приложения Qt Widget , который я создал.Но когда я запускаю его, бинарный файл остается пустым.Не могли бы вы помочь мне с этим.Кроме того, есть ли лучший способ сделать такое?

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

Комментарий: В качестве ссылки эта ссылка показывает аналогичную проблему, но я не смог правильно понять / реализовать предложения.Например, я попытался определить новый оператор, как это объяснено здесь , но он не работал.

Ответы [ 2 ]

0 голосов
/ 14 сентября 2018

Вот пример, который работал для меня после выполнения всех исправлений.В этом примере показано, как сохранить / загрузить struct или class в файл с помощью QDataStream.Структура, то есть myStruct , имеет три члена: int, string и struct, то есть mySubStruct .

  • Для каждого struct / class необходимо перегрузить операторы << и >>.
  • В каждом перегруженном операторе сохранить / загрузить структурудостигается путем разбиения структуры на ее примитивные члены .Примитивными членами являются типы, которые поддерживаются QDataStream .

comment 1: В следующем примере используется перегрузка операторов в struct.Чтобы узнать, как перегрузить операторы на class, см. эту ссылку .

комментарий 2: Эта ссылка является полным примером.

mysubstruct.h

#ifndef MYSUBSTRUCT_H
#define MYSUBSTRUCT_H

#include <QString>
#include <QDataStream>

struct mySubStruct
{
    int intVar;
    QString strVar;

    /* overload the operators */
    friend QDataStream &operator<< (QDataStream &out, const mySubStruct &rhs)
    {
        out << rhs.intVar << rhs.strVar;
        return out;
    }

    friend QDataStream &operator>> (QDataStream &in, mySubStruct &rhs)
    {
        in >> rhs.intVar >> rhs.strVar;
        return in;
    }
};
#endif // MYSUBSTRUCT_H

mystruct.h

#ifndef MYSTRUCT_H
#define MYSTRUCT_H

#include <QString>
#include <QDataStream>
#include "mysubstruct.h"

struct myStruct
{
    int intVar;
    QString strVar;
    mySubStruct subStructObj;

    /* overload the operators */
    friend QDataStream &operator<< (QDataStream &out, const myStruct &rhs)
    {
        out << rhs.intVar << rhs.strVar << rhs.subStructObj;
        return out;
    }

    friend QDataStream &operator>> (QDataStream &in, myStruct &rhs)
    {
        in >> rhs.intVar >> rhs.strVar >> rhs.subStructObj;
        return in;
    }
};
#endif // MYSTRUCT_H

mainwindow.h

#ifndef MAINWINDOW_H
#define MAINWINDOW_H

#include <QMainWindow>
#include <QFile>
#include <QString>
#include <QDebug>
#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_H

mainwindow.cpp показывает, как реализованы операторы.

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

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

    /* create struct */
    mySubStruct subStructIn;
    subStructIn.intVar = 1;
    subStructIn.strVar = "a";

    myStruct structIn;
    structIn.intVar = 11;
    structIn.strVar = "aa";
    structIn.subStructObj = subStructIn;

     /* open file */
     QFile myFile("myFile");

     /* save */
     if(myFile.open(QIODevice::WriteOnly))
     {
         QDataStream save(&myFile);
         save.setVersion(QDataStream::Qt_4_6);
         save << structIn;
         myFile.close();
     }

     /* load */
     myStruct structOut;
     if(myFile.open(QIODevice::ReadOnly))
     {
         QDataStream load(&myFile);
         load.setVersion(QDataStream::Qt_4_6);
         load >> structOut;
         myFile.close();
     }

     qDebug() << structOut.intVar;
     qDebug() << structOut.strVar;
     qDebug() << structOut.subStructObj.strVar;
     qDebug() << structOut.subStructObj.intVar;
}

MainWindow::~MainWindow()
{
    delete ui;
}
0 голосов
/ 13 сентября 2018

Прежде всего, вы не должны сохранять указатель, так как это только адрес памяти переменной, то, что должно быть сохранено, это значение.С другой стороны, если вы хотите использовать QDataStream, вы должны переписать потоковые операторы, наконец, если вы хотите сохранить как QVariant, вы должны использовать qRegisterMetaTypeStreamOperators.В дополнение к вышесказанному в вашем коде есть несколько ошибок, таких как не открытие 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;
}
...