Didac Perez Parera
Didac Perez Parera

Reputation: 3824

Serialize a data structure in text format in C++/Qt

I need to store some data structure into a SQL database. This data may vary so I could not know which fields the database must have. I am about to do it encoding the data structure into a XML or JSON object and then put it into the SQL database. But it could not work, so I need serialization, since the problem is about encoding that structure.

Which library/tool/method may I use to serialize/deserialize a data structure into a text? Let's say a data structure composed by some Integers, some Unicode strings, and some Booleans.

Many thanks in advance!

Upvotes: 1

Views: 4047

Answers (3)

SigTerm
SigTerm

Reputation: 26429

since the problem is about encoding that structure.

Qt can't automatically serialize things, so you'll have to write some kind of routine to save/load your data. Exact solution depends on your requirements and how are you going to use data.

Things you should consider:

  1. Is human-readability required? (loading text file can be slower, due to parsing)
  2. Is communication/data exchange (with some other program) required?
  3. What is least-expensive development solution?

Recommendation:

  1. If data is simple, used only by your app, binary(non-human readable), then use QDataStream + QByteArray, serialize by hand.
  2. If data is complex, used only by your app, binary(non-human readable), then use QDataStream + QByteArray + QVariantMap. (dump data into qvariant map, then serialize it into QByteArray using QDataStream)
  3. If data is simple, used only by your app, text(should be human readable) then plain text, json or xml.
  4. If data is complex, used only by your app, text(human readable), then use json or xml - depending on whichever is available/whichever is shortest.
  5. If data is supposed to be read by some 3rd party tool, then use whatever format this tool uses.

Details:

If you're communicating with something, you're stuck with whatever format the thing you communicate with is using. That'll be probably either json or xml, because various scripting langauges frequently can easily read either of them

If data is supposed to be human-readable, then you have following options: plain text, json or xml, depending on data format/complexity. (ini won't work in your scenario, because it is supported by QSettings that doesn't really serialize to random in-memory location. xml/json) can store tree-like structures, but json is available in Qt 4 only via external dependency, and xml reader/writer requires effort to get hang of it.

If you want to store private data (used only by your application) that is not human readable and is only used by your application, you can use pretty much whatever you want, including binary format.

The simplest way would be to dump it into QByteArray + QDataStream manually, because QDataStream guarantees that binary data will be correctly loaded on any platform regardless of endianness (as long as you don't dump it as a raw memory block, that is). That'll work fine if data is simple array of similar structures that has fixed number of components that are always present.

If the data is tree-like and has optional nodes (i.e. tree of key-value pairs, where value can be another tree) and keys may or may not be present, you'll library or routine that deals with those key/value pair trees. In Qt 4 that's QVariantMap and xml (via QXmlStreamWriter/QXmlStreamReader). Qt 5 also has json support. In case when multiple solutions are available, built-in solution that takes least amount of effort to implement, wins. Reading a named field from QVariantMap takes 1 line of code per value + a helper function that is roughly 10 lines of code, it also supports all Qt 4 types.

QVariantMap has significant advantage other json in a sense that it supports all Qt types natively as values. I.e. you can easily dump QColor, QPoint, plus you types you registered into it. Anything you can store in QVariant, you can store within QVariantMap, which can then be serialized to/from QDataStream in a single line of code.

Json, on other hand, has advantage of being "standard" data format that can be loaded within scripting language. That is at cost of having only 6 basic types it supports.

Json is not supported natively by Qt 4, and although there is QJson, adding external dependencies is not always a good idea, because you're going to babysit them. If you're using Qt 4 and really need json support, it might make sense to upgrade to Qt 5.

Upvotes: 5

gbdivers
gbdivers

Reputation: 1147

What do you do with this data in the database? If you want to use it in another program or language, then your data need to be readable and you can use QXmlStreamWriter/Reader or QJsonDocument (both with QByteArray).

If you don't want to use your data outside your program, you can write them in QByteArray with QDataStream.

It would be something like the code below.

QByteArray data;
QDataStream stream(&data);
stream << yourClasses;
sqlQuery.bindValue(data);

You just need to add stream operators in your classes you want to serialize:

QDataStream &operator<<(QDataStream &, A const&);
QDataStream &operator>>(QDataStream &, A &);

Upvotes: 4

L&#225;szl&#243; Papp
L&#225;szl&#243; Papp

Reputation: 53165

This is a long and detailed answer, but here goes the point. Qt 5.2 has an example how you could achieve all this with Qt based on the "SaveGame" example which is also doing the serialization and deserialization. It is basically doing that for the non-playable game character. It is also using QSaveFile for saving the information safely into the desired file. Here you can find the url to the documentation of the example for your convenience:

http://doc-snapshot.qt-project.org/qdoc/qtcore-savegame-example.html

I have just solved this issue a few days ago with Qt5's json parser. I would suggest to take a look into the following classes:

If you are planning to use Qt 4, you will need to use the QJson library for instance, but mind you, it is a lot slower than the Qt 5 json parser based on the performance. Here you can find Thiago's benchmark:

https://plus.google.com/108138837678270193032/posts/7EVTACgwtxK

The json format supports strings, integers, and bool just as you wish, so that should work for you. Here you can find the signatures how to serialize and deserialize such types:

Serialize

bool    toBool(bool defaultValue = false) const
double  toDouble(double defaultValue = 0) const
QString toString(const QString & defaultValue = QString()) const

Deserialize

QJsonValue(bool b)
QJsonValue(double n)
QJsonValue(const QString & s)

Here you can find a summary page about the json support in Qt 5:

http://doc-snapshot.qt-project.org/qt5-nosubdir/json.html

Note that, Qt 5's json is saved internally as a very efficient binary representation, so essentially you could also use that rather than text representation. It depends on your exact scenario. Actually, for Qt 4, you could even backport these classes if needed since they are so much tied to Qt 5. It may have actually been so for BlackBerry development since we were struggling with Qt 4 there, and we badly needed the json parser from Qt.

Upvotes: 3

Related Questions