[ fromfile: serializer.xml id: serializer ]
With QDataStream, it is already possible to serialize and deserialize all QVariant-supported types, including QList, QMap, QVector, and others.
With QTextStream, if you want the extraction (>>) operator to work with the output of the insertion (<<) operator on your custom type, you must define proper field and record delimiters for the string types, and write and test the operators properly with sample data.
Example 7.3 shows the friend declarations of input/output operator functions of MetaDataValue, a class used for storing song metadata.
the operators should not be member functions of MetaDataValue
the idea of the serializer pattern is to separate the I/O code from the class itself.
The METADATAEXPORT macro facilitates the reuse of this code on a Windows platform.[35]
Example 7.3. src/libs/metadata/metadatavalue.h
[ . . . . ] class METADATAEXPORT MetaDataValue { public: friend METADATAEXPORT QTextStream& operator<< (QTextStream& os, const MetaDataValue& mdv); friend METADATAEXPORT QTextStream& operator>> (QTextStream& is, MetaDataValue& mdv); friend METADATAEXPORT QDataStream& operator<< (QDataStream& os, const MetaDataValue& mdv); friend METADATAEXPORT QDataStream& operator>> (QDataStream& is, MetaDataValue& mdv); friend METADATAEXPORT bool operator==(const MetaDataValue&, const MetaDataValue&); [ . . . . ] virtual QString fileName() const ; virtual Preference preference() const ; virtual QString genre() const; virtual QString artist() const; virtual QString albumTitle() const; virtual QString trackTitle() const; virtual QString trackNumber() const; virtual const QImage &image() const; virtual QTime trackTime() const; virtual QString trackTimeString() const; virtual QString comment() const; [ . . . . ] protected: bool m_isNull; QUrl m_Url; QString m_TrackNumber; QString m_TrackTitle; QString m_Comment; Preference m_Preference; QString m_Genre; QString m_Artist; QTime m_TrackTime; QString m_AlbumTitle; QImage m_Image; }; Q_DECLARE_METATYPE(MetaDataValue); [ . . . . ]
Add to QVariant type system. |
Each operator returns a reference to the left operand to enable chaining.
The QTextStream operators in Example 7.4 need to be concerned with whitespace and delimiters because everything is streamed out in string representations.
Example 7.4. src/libs/metadata/metadatavalue.cpp
[ . . . . ] QTextStream& operator<< (QTextStream& os, const MetaDataValue& mdv) { QStringList sl; sl << mdv.url().toString() << mdv.trackTitle() << mdv.artist() << mdv.albumTitle() << mdv.trackNumber() << mdv.trackTime().toString("m:ss") << mdv.genre() << mdv.preference().toString() << mdv.comment(); os << sl.join("\t") << "\n"; return os; } QTextStream& operator>> (QTextStream& is, MetaDataValue& mdv) { QString line = is.readLine(); QStringList fields = line.split("\t"); while (fields.size() < 9) { fields << ""; } mdv.m_isNull = false; mdv.setUrl(QUrl::fromUserInput(fields[0])); mdv.setTrackTitle(fields[1]); mdv.setArtist(fields[2]); mdv.setAlbumTitle(fields[3]); mdv.setTrackNumber(fields[4]); QTime t = QTime::fromString(fields[5], "m:ss"); mdv.setTrackTime(t); mdv.setGenre(fields[6]); Preference p(fields[7]); mdv.setPreference(p); mdv.setComment(fields[8]); return is; }
The QDataStream operators, shown in Example 7.5, are much simpler to use because they relieve the programmer of the responsibility for separating data items from one another.
Example 7.5. src/libs/metadata/metadatavalue.cpp
[ . . . . ] QDataStream& operator<< (QDataStream& os, const MetaDataValue& mdv) { os << mdv.m_Url << mdv.trackTitle() << mdv.artist() << mdv.albumTitle() << mdv.trackNumber() << mdv.trackTime() << mdv.genre() << mdv.preference() << mdv.comment() << mdv.image(); return os; } QDataStream& operator>> (QDataStream& is, MetaDataValue& mdv) { is >> mdv.m_Url >> mdv.m_TrackTitle >> mdv.m_Artist >> mdv.m_AlbumTitle >> mdv.m_TrackNumber >> mdv.m_TrackTime >> mdv.m_Genre >> mdv.m_Preference >> mdv.m_Comment >> mdv.m_Image; mdv.m_isNull= false; return is; }
Example 7.6 shows how to use these operators with the different streams.
Example 7.6. src/serializer/testoperators/tst_testoperators.cpp
[ . . . . ] void TestOperators::testCase1() { QFile textFile("playlist1.tsv"); QFile binaryFile("playlist1.bin"); QTextStream textStream; QDataStream dataStream; if (textFile.open(QIODevice::ReadOnly)) { textStream.setDevice(&textFile); } if (binaryFile.open(QIODevice::WriteOnly)) { dataStream.setDevice(&binaryFile); } QList<MetaDataValue> values; while (!textStream.atEnd()) { MetaDataValue mdv; textStream >> mdv; values << mdv; dataStream << mdv; } textFile.close(); binaryFile.close(); textFile.setFileName("playlist2.tsv"); if (binaryFile.open(QIODevice::ReadOnly)) { dataStream.setDevice(&binaryFile); for (int i=0; i<values.size(); ++i) { MetaDataValue mdv; dataStream >> mdv; QCOMPARE(mdv, values[i]); } } } [ . . . . ]
Generated: 2012-03-02 | © 2012 Alan Ezust and Paul Ezust. |