Qt Jambi 4.4文档翻译:QDataStream类,Class QDataStream

- no title specified

Qt Jambi 4.4文档翻译:QDataStream类,Class QDataStream

QDataStream类提供咯将二进制数据序列化到一个QIODevice 中去的功能。一个数据流就是一个代表已编码信息的二进制流,它是与所运行的电脑的操作系统、中央处理器或者字节序完全无关的。例如,使用Windows 的PC 所生成的一个数据流可以被运行Solaris 的Sun SPARC 读取。

你也可以使用一个数据流来读写未编码的二进制数据。如果你想使用一个带有“分词”(”parsing”)功能的输入流,那么就去看看QTextStream

QDataStream类实现咯对C++的基本数据类型的序列化,例如charshortintchar *等等。对更复杂的数据的序列化是通过将数据分解成原子单位来实现的

一个数据流与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 类型包括QBrushQColorQDateTimeQFontQPixmapQString(本座告诉你,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 以外)的任何编码/解码工作要由你来做。

参见

QTextStreamQVariant