Qt Jambi 4.4文档翻译:QDataStream类,Class QDataStream
QDataStream类提供咯将二进制数据序列化到一个QIODevice 中去的功能。一个数据流就是一个代表已编码信息的二进制流,它是与所运行的电脑的操作系统、中央处理器或者字节序完全无关的。例如,使用Windows 的PC 所生成的一个数据流可以被运行Solaris 的Sun SPARC 读取。
你也可以使用一个数据流来读写未编码的二进制数据。如果你想使用一个带有“分词”(”parsing”)功能的输入流,那么就去看看QTextStream。
QDataStream类实现咯对C++的基本数据类型的序列化,例如char、short、int、char *等等。对更复杂的数据的序列化是通过将数据分解成原子单位来实现的。
一个数据流与QIODevice 是紧密结合的。一个QIODevice表示一个输入/输出介质,你可以从中读取数据,也可以向其中写入数据。QFile 类就是输入/输出设备的一个例子。
示例(向一个流中写入二进制数据):
QFile file = new QFile(“file.dat”);
QFile.OpenMode mode = new QFile.OpenMode();
mode.set(QFile.OpenModeFlag.WriteOnly);
file.open(mode);
QDataStream out = new QDataStream(file); //我们会将数据序列化到file中
out.writeString(“the answer is”); //序列化一个字符串
out.writeInt(42); //序列化一个整数
示例(从一个流中读取二进制数据):
QFile file = new QFile(“file.dat”);
QFile.OpenMode mode = new QFile.OpenMode();
mode.set(QFile.OpenModeFlag.ReadOnly);
file.open(mode);
QDataStream in = new QDataStream(file); //从file中读取序列化后的数据
//提取”the answer is”和42
String str = in.readString();
int a = in.readInt();
写入到流中的每个条目都是以一个预定义的二进制格式写入的,这个格式根据条目的类型而变化。所支持的Qt 类型包括QBrush、QColor、QDateTime、QFont、QPixmap、QString(本座告诉你,QtJambi中没有QString)、QVariant和其它的很多类型。要想知道支持数据流的Qt 类型的完整列表,就去看QDataStream操作符的格式。
对于整数,最好在写入之前转换成一个Qt 整数,并且在读取的时候以那个相同的Qt 整数的类型来读取。这样能确保你得到你想要的大小的整数,并且将你与编译器和平台的差异隔离开。
举个例子吧,一个char *字符串是勒样写入的:一个32位的整数,表示的是包括’\0′字节在内的字符串的长度,紧接着是包含’\0′字节在内的整个字符串的各个字符。当读取一个char *字符串时,首先读取4字节,将它作为那个32 位的长度值,再读取那么多的字符,以构造那个char *字符串,其中包括’\0′终结符。
初始的输入/输出设备通常是在构造函数里设置的,但是可以使用setDevice()来修改。如果你到达咯数据的末尾(或者没有设置输入/输出设备),那么atEnd()就会返回真。
版本设置
QDataStream的二进制格式从Qt 1.0 以来一直在变化,并且看样子会随着Qt 的变化而继续变化。当你在输入或者输出复杂的类型时,要确保是使用相同版本的流(version())来读取和写入的。如果你同时需要前向和后向兼容性,那么你可以将版本号硬编码到程序中:
stream.setVersion(QDataStream.Version.Qt_4_0.value());
如果你在创建一个新的二进制数据格式,例如由你的程序所创建的文档所使用的一个文件格式,那么你可以使用QDataStream 来按照一个可移植的格式来写这些数据。典型地,你可以写入一个简短的文件头,其中包含一个魔数字符串和一个版本号,这样就给你自己留下咯在将来进行扩展的空间。例如:
QFile file = new QFile(“file.xxx”);
QFile.OpenMode mode = new QFile.OpenMode();
mode.set(QFile.OpenModeFlag.WriteOnly);
file.open(mode);
QDataStream out = new QDataStream(file);
//写入一个包含“魔数”和一个版本号的文件头
out.writeInt(0xA0B0C0D0);
out.writeInt(123);
out.setVersion(QDataStream.Version.Qt_4_0.value());
//写入数据
out.writeBytes(lots_of_interesting_data.toByteArray());
以后再像这样读取:
QFile file = new QFile(“file.xxx”);
QFile.OpenMode mode = new QFile.OpenMode();
mode.set(QFile.OpenModeFlag.ReadOnly);
file.open(mode);
QDataStream in = new QDataStream(file);
//读取并且检查文件头
int magic = in.readInt();
if (magic != 0xA0B0C0D0)
return XXX_BAD_FILE_FORMAT;
//读取版本号
int version = in.readInt();
if (version < 100)
return XXX_BAD_FILE_TOO_OLD;
if (version > 123)
return XXX_BAD_FILE_TOO_NEW;
if (version <= 110)
in.setVersion(QDataStream.Version.Qt_3_1.value());
else
in.setVersion(QDataStream.Version.Qt_4_0.value());
//读取数据
QByteArray lots_of_interesting_data = new QByteArray();
QByteArray data_new_in_XXX_version_1_2 = new QByteArray();
QByteArray other_interesting_data = new QByteArray();
lots_of_interesting_data.readFrom(in);
if (version >= 120)
data_new_in_XXX_version_1_2.readFrom(in);
other_interesting_data.readFrom(in);
你可以选择在序列化数据时使用什么字节序。默认的设置是大端在前(最重要的字节(MSB)在前)。如果将它改变成小端在前的话会破坏可移植性(除非读取者也变成小端在前)。我们建议保留这个设置,除非你有特殊的需求。
读取和写入原始的二进制数据
你可能想要从数据流/向数据流直接读取/写入你自己的原始二进制数据。可以使用readRawData()来从流中将数据读取到一个预先分配咯空间的char *中。可以使用writeRawData()来将类似的数据写入到流中。注意,任何的编码/解码工作都必须由你来做。
类似的一对函数是readBytes()和writeBytes()。它们与对应的原始(raw)函数有以下不同:readBytes()首先会读取一个quint32,将它作为要读取的数据的长度,然后将那么多的数据读取到一个预先分配咯空间的char *中;writeBytes()首先写入一个quint32,它表示的是数据的长度,接下来就写入数据。注意,对数据(除咯那个表示长度的quint32 以外)的任何编码/解码工作要由你来做。
参见: