我需要从项目中序列化和解析多个对象,以便在需要时保存/加载它们。
我的对象将具有完全相同的组件: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或使用QJsonArrays创建QJsonObject的QJsonArray吗?
当我阅读它时,我需要检查id;但是会
foreach(object.value["id"] == 42)
//create the QJsonObject from the one with 42 and change it with the new data
会解析对象而不是所有对象吗?还有更好的方法吗?
提前感谢您的回答。
答案 0 :(得分:0)
你可以拥有一个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数据。
使用存储在文件开头的查找表可以进一步改善这一点。