如何在 Qt 中使用 QDataStream 将自定义结构 Save/Load 转换为二进制文件?
How to Save/Load a custom struct into a binary file using QDataStream in Qt?
我打算将一个结构保存在一个二进制文件中,稍后加载它。我发现一种方法是使用 QVariant
。这是我创建的一个简化的 Qt Widget Application 示例。但是当我 运行 它时,二进制文件仍然是空的。你能帮我一下吗?另外,有没有更好的方法来做这样的事情?
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
评论:作为参考,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,但没用。
首先你不应该保存指针,因为这只是变量的内存地址,应该保存的是值。另一方面,如果你想使用 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;
}
这是在完成所有更正后对我有用的示例。此示例显示我如何使用 QDataStream
save/load 一个 struct
或一个 class
到一个文件中。该结构,即 myStruct,具有三个成员:int
、string
和 struct
,即 mySubStruct。
- 对于每个
struct
/class
,需要重载 <<
和 >>
运算符。
- 在每个重载运算符中,结构的 save/load 是通过 将结构分解为其原始成员 来完成的。原始成员是 the types that are supported by QDataStream.
评论 1: 下面的示例使用重载运算符到 struct
。要查看如何将运算符重载为 class
,请参阅 this link.
评论2: This link是一个完整的例子。
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;
}
我打算将一个结构保存在一个二进制文件中,稍后加载它。我发现一种方法是使用 QVariant
。这是我创建的一个简化的 Qt Widget Application 示例。但是当我 运行 它时,二进制文件仍然是空的。你能帮我一下吗?另外,有没有更好的方法来做这样的事情?
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
评论:作为参考,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,但没用。
首先你不应该保存指针,因为这只是变量的内存地址,应该保存的是值。另一方面,如果你想使用 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;
}
这是在完成所有更正后对我有用的示例。此示例显示我如何使用 QDataStream
save/load 一个 struct
或一个 class
到一个文件中。该结构,即 myStruct,具有三个成员:int
、string
和 struct
,即 mySubStruct。
- 对于每个
struct
/class
,需要重载<<
和>>
运算符。 - 在每个重载运算符中,结构的 save/load 是通过 将结构分解为其原始成员 来完成的。原始成员是 the types that are supported by QDataStream.
评论 1: 下面的示例使用重载运算符到 struct
。要查看如何将运算符重载为 class
,请参阅 this link.
评论2: This link是一个完整的例子。
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;
}