對於純綷的二進位資料,可以使用QDataStream來協助處理,可以直接處理C++基本資料型態、還有許多Qt資料型態,像是QByteArray、QString、QMap等,可以使用 << 或 >> 運算子來進行資料輸出或寫入。
先使用以下的簡單例子,示範一下QDataStream搭配QFile來進行檔案讀寫:
#include <QFile>
#include <QDataStream>
#include <QString>
#include <QMap>
#include <iostream>
using namespace std;
int main(int argc, char *argv[]) {
QFile file("data.dat");
QMap<QString, int> map;
map.insert("caterpillar", 95);
map.insert("momor", 93);
if(!file.open(QIODevice::WriteOnly)) {
cerr << "Cannot open file for writing: "
<< qPrintable(file.errorString()) << endl;
return false;
}
QDataStream out(&file);
// 設定QDataStream支援版本
out.setVersion(QDataStream::Qt_4_3);
// 寫入資料
out << 1 << map;
file.close();
if(!file.open(QIODevice::ReadOnly)) {
cerr << "Cannot open file for reading: "
<< qPrintable(file.errorString()) << endl;
return false;
}
QDataStream in(&file);
// 設定QDataStream支援版本
in.setVersion(QDataStream::Qt_4_3);
int num = 0;
QMap<QString, int> inMap;
// 讀入資料
in >> num >> inMap;
cout << "num: " << num << endl
<< "map: <caterpillar, " << inMap.value("caterpillar") << ">" << endl
<< "map: <momor, " << inMap.value("momor") << ">" << endl;
return true;
}
程式中可以看到setVersion()方法,這設定QDataStream讀寫時的版本,因為Qt的物件成員等資料,會隨著不同版本而可能有所不同,例如QMap新版中可能有一些成員屬性是舊版本所沒有的,使用setVesrion()設定Qt支援的讀寫版本,告訴QDataStream在寫入或讀取時應當處理的物件資料。
程式執行時的結果如下所示:
num: 1
map: <caterpillar, 95>
map: <momor, 93>
map: <caterpillar, 95>
map: <momor, 93>
QDataStream也可以直接處理位元資料,例如使用 readRawBytes()與writeRawBytes()來進行原始位元資料的處理。QDataStream處理數值時,預設使用big- endian的方式,如果您要改變為使用little-endian,則可以使用setByteOrder()方法設定為QDataStream:: LittleEndian。
如果想要QDataStream可以使用 << 或 >> 來支援您的自訂義物件,則您需要重載 << 與 >> 運算子,告訴QDataStream如何儲存或讀取物件,例如:
#include <QFile>
#include <QDataStream>
#include <QString>
#include <iostream>
using namespace std;
class Dog {
public:
Dog() { _number = 0; }
Dog(int number, const QString &name) {
_number = number;
_name = name;
}
void setNumber(int number) { _number = number; }
int number() const { return _number; }
void setName(const QString &name) { _name = name; }
QString name() const { return _name; }
private:
int _number;
QString _name;
};
QDataStream &operator<<(QDataStream &out, const Dog &dog) {
out << dog.number() << dog.name();
return out;
}
QDataStream &operator>>(QDataStream &in, Dog &dog) {
int number = 0;
QString name;
in >> number >> name;
dog.setNumber(number);
dog.setName(name);
return in;
}
int main(int argc, char *argv[]) {
QFile file("data.dat");
Dog dog1(1, "caterpillar");
Dog dog2(2, "momor");
if(!file.open(QIODevice::WriteOnly)) {
cerr << "Cannot open file for writing: "
<< qPrintable(file.errorString()) << endl;
return false;
}
QDataStream out(&file);
out.setVersion(QDataStream::Qt_4_3);
out << dog1 << dog2;
file.close();
if(!file.open(QIODevice::ReadOnly)) {
cerr << "Cannot open file for reading: "
<< qPrintable(file.errorString()) << endl;
return false;
}
QDataStream in(&file);
in.setVersion(QDataStream::Qt_4_3);
in >> dog1 >> dog2;
cout << dog1.number() << ", " << qPrintable(dog1.name()) << endl
<< dog2.number() << ", " << qPrintable(dog2.name()) << endl;
return true;
}
程式執行時的結果如下所示:
1, caterpillar
2, momor
2, momor
如以上重載 << 與 >> 運算子,還有一個好處,就是可以讓自定義物件支援QList等容器之 << 與 >> 之附加與取出,例如像以下的操作:
QList<Dog> list;
Dog dog1(1, "caterpillar");
Dog dog2(2, "momor");
list << dog1 << dog2;
QList<Dog>::const_iterator iterator = list.begin();
while(iterator != list.end()) {
cout << (*iterator).number() << ", "
<< qPrintable((*iterator).name()) << endl;
++iterator;
}
Dog dog1(1, "caterpillar");
Dog dog2(2, "momor");
list << dog1 << dog2;
QList<Dog>::const_iterator iterator = list.begin();
while(iterator != list.end()) {
cout << (*iterator).number() << ", "
<< qPrintable((*iterator).name()) << endl;
++iterator;
}