在Qt C ++中

时间:2017-06-29 22:52:47

标签: c++ json qt

我需要从项目中序列化和解析多个对象,以便在需要时保存/加载它们。

我的对象将具有完全相同的组件: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

会解析对象而不是所有对象吗?还有更好的方法吗?

提前感谢您的回答。

1 个答案:

答案 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数据。

使用存储在文件开头的查找表可以进一步改善这一点。