在Qt C++中序列化/解析一个文件中的多个对象
Serializing/parsing multiple objects in one file in Qt C++
我需要序列化和解析项目中的多个对象,以便在需要时保存/加载它们。
我的对象将具有完全相同的组件:一个 QString 名称、一个整数 id、一个 QString 描述和两个整数 x、y。 我需要这样的东西:
{"name":"toto", "id":"42", "description":"tata", "x":"20", "y":"50"}
所以我会像这样构建我的QJsonObject:
QJsonObject json;
json["id"] = object_to_serialize.get_id();
json["name"] = object_to_serialize.get_name();
json["description"] = object_to_serialize.get_description();
json["x"] = object_to_serialize.get_x();
json["y"] = object_to_serialize.get_y();
QJsonDocument filedoc(json);
file.write(filedoc.toJson);`
在文件中,它将如下所示:
{"name":"toto", "id":"42", "description":"tata", "x":"20", "y":"50"}
{"name":"toto2", "id":"44", "description":"tata2", "x":"25", "y":"547"}
{"name":"toto3", "id":"46", "description":"tata3", "x":"21", "y":"580"}
我的序列化程序将接收参数对象、保存文件名,并将对象转换为 QJsonObject。然后,它将需要读取文件以检查此处是否存在具有相同 id 的对象。如果它在这里,它将需要替换它,如果它不是,它将附加它。
我在序列化选项和如何阅读它之间有点迷茫;
我应该制作一个包含多个 QJsonObject 的 QJsonArray 还是使用 QJsonArrays 的 QJsonObject ?
当我阅读它时,我需要检查 id ; 但会
foreach(object.value["id"] == 42)
//create the QJsonObject from the one with 42 and change it with the new data
将解析对象而不是全部?有没有更好的方法?
提前感谢您的回答。
你可以有一个 json 对象的数组,每个对象都有一个 ID,以便你可以解析相关的对象。
虽然你也可以解析所有这些文件并将它们添加到地图中,但只要你没有很重的文件,它应该没问题。
void parseJson(const QString &data)
{
QJsonDocument doc = QJsonDocument::fromJson(data.toUtf8());
if (doc.isNull())
{
war("invalid json document");
return;
}
QJsonArray jsonArray = doc.array();
foreach (const QJsonValue & value, jsonArray) {
QJsonObject obj = value.toObject();
if (obj.contains("id"))
{
if (obj["id"].toInt() == yourId) parseObject(obj);
}
}
}
void parseObject(const QJsonObject &obj)
{
if (obj.contains("valueA")) valueA = obj["valueA"].toDouble();
if (obj.contains("valueB")) valueB = obj["valueB"].toDouble();
}
如果您的文件不是太大,这将正常工作
>更大的文件现在,如果您有非常大的文件,将其全部加载到内存中并解析它可能会有问题。
由于您的结构始终相同且非常简单,因此 JSON 可能不是最佳选择,一种更有效的方法是执行您自己的解析器(或使用一些现有的解析器(,它可以读取文件并将其作为流处理。
另一种方法是每行有一个 JSON 条目,前面有一个固定位数的 ID。在 QHash 查找中加载它,然后只从文件中读取感兴趣的 id,并且只解析一小部分。
// This code is not tested and is just to show the principle.
#define IDSIZE 5
QHash<int64, int64> m_lookup; // has to be global var
// For very large file, this might take some time and can be done on a separate thread.
// it needs to be done only once at startup (given the file is not modified externally)
void createLookup(const QString &fileName)
{
QFile inputFile(fileName);
if (inputFile.open(QIODevice::ReadOnly))
{
QTextStream in(&inputFile);
while (!in.atEnd())
{
int position = in.pos(); // store the position in the file
QString line = in.readLine();
int id = line.mid(0,IDSIZE).toInt(); // 5 digit id (like 00001, 00002, etc...
m_lookup[id] = position + IDSIZE;
}
inputFile.close();
}
}
QString getEntry(const QString &fileName, int64 id)
{
if (m_lookup.contains(id))
{
QFile inputFile(fileName);
if (inputFile.open(QIODevice::ReadOnly))
{
inputFile.seek(m_lookup[id]);
QString data = inputFile.readLine();
inputFile.close();
return data;
} else {
return QString(); // or handle error
}
} else {
return QString(); // or handle error
}
}
// use example
QString data = getEntry(id);
if (data.length() > 0)
{
QJsonDocument doc = QJsonDocument::fromJson(data.toUtf8());
if (!doc.isNull())
{
// assign your variables
}
}
您的数据文件如下所示:
00042{"name":"toto", "id":"42", "description":"tata", "x":"20", "y":"50"}
00044{"name":"toto2", "id":"44", "description":"tata2", "x":"25", "y":"547"}
00046{"name":"toto3", "id":"46", "description":"tata3", "x":"21", "y":"580"}
这种方法的优点是,它只会读取感兴趣的条目,而不必为了获取特定条目而在内存中加载MB或GB的数据。
这可以通过使用存储在文件开头的查找表来进一步改进。
- 挂起和取消挂起一个文件DLL
- 输入到文件并输出到另一个文件,并将流文件传递给函数
- C++试图读取一个文件并输出到另一个文本文件
- 如何从另一个文件继承私有成员变量和公共函数
- 在 Windows 上,是否可以让 dll 在不使用 PATH 环境变量的情况下在另一个文件夹中查找依赖项?
- 如何将class.cpp和class.hpp编译为一个.o文件
- 如何在 Gnuplot 中分别绘制 2 个文件数据?我有一个文件"sin.txt",另一个文件"cos.txt",我想将它们分别绘制在一个图表上
- 如何从整个磁盘中排除要装载的一个文件
- 如何将模板和非模板函数放在一个文件中
- 如何在安卓工作室中将c ++头文件从一个文件夹导入到另一个文件夹?
- 使用 scope 运算符 (::) 引用另一个文件中的类
- JNI,使用两个 .so 文件时出错,其中一个文件需要另一个文件
- 为什么我不能从同一目录中的另一个文件中 #include 我的类?
- 在 c++ 中打开文件、删除标点符号并追加到另一个文件中
- C++ 如何将两个 makefile 对象目标规则(位于另一个文件夹中)合并到一个目标/规则中?
- 是否可以将子进程的 stdout 重定向到父进程中的另一个文件?
- c++ 提升如果 .extension() == " "这意味着这个文件是一个文件夹?
- 是否可以在 c++ 中创建一个文件并为其提供属性以将其隐藏?(在 Ubuntu 上)
- 我需要编写一个程序来读取一个文件,该文件将输出所有唯一的整数,如果已经看到整数,它将被关闭
- 如何在标准c ++中流式传输/读取二进制文件的中间部分并写入另一个文件?