python3二进制文件读写,python二进制文件的读取与写入分别使用什么方法
在上一章中,我们介绍了QFile和QFileInfo的用法。我们提到QIODevice提供了read()和readLine()等基本操作。同时,Qt还提供了更高层次的操作:针对二进制的流QDataStream和针对文本流的QTextStream。在本节中,我们将解释QDataStream的使用方法和一些技巧。下一章是关于QTextStream的。
QDataStream基于QIODevice提供二进制数据的序列化。数据流是二进制流,完全独立于底层操作系统、CPU或字节顺序(大端或小端)。例如,在装有Windows平台的PC上编写的数据流可以在运行Solaris的SPARC机器上直接读取,无需任何处理。由于数据流是二进制流,所以我们也可以不编码直接读写二进制数据,比如图像、视频、音频等。
QDataStream不仅可以访问基本的C类型,如int、char、short等。但也包括复杂的数据类型,如自定义类。实际上,QDataStream通过将复杂的类分成许多基本单元来存储类。
结合QIODevice,QDataStream可以轻松读写文件、网络套接字等。让我们从代码开始:
QFile文件( file . dat );file . open(QIODevice:write only);QDataStream out(文件);out QString(答案是);out(qint 32)42;在这段代码中,我们首先打开一个名为file.dat的文件(注意,为了简单起见,我们没有检查文件是否被成功打开,这在正式的过程中是不允许的)。然后,我们将刚刚创建的file对象的指针传递给一个QDataStream实例。类似于std:cout标准输出流,QDataStream也重载输出重定向运算符。下面的代码很简单:输出“答案是”和数字42到数据流(如果你不明白这句话的意思,这是宇宙终极问题的答案;-P请自行搜索《银河系漫游指南》)。既然我们的out对象是建立在file上的,就相当于把宇宙终极问题的答案写入了file。
需要指出的是,读写最好使用Qt整数,比如程序中的qint32。这确保了在任何平台和任何编译器上的相同行为。
我们通过一个例子来看看Qt是如何存储数据的。例如,将首先存储char *字符串,包括\0终止符(32位整数)的长度,然后是字符串和终止符\0的内容。读取时,将整个长度作为32位整数读出,然后根据这个长度取出整个字符串的内容。
但是,如果直接运行这段代码,将会得到一个没有写入数据的空白file.dat。这是因为我们的文件没有正确关闭。为了提高性能,只有在文件关闭时才会实际写入数据。因此,我们必须在末尾添加一行代码:
file . close();//如果不想关闭文件,可以使用file . flush();
再运行一下程序,就OK了。
我们已经找到了宇宙终极问题的答案。现在,我们将宣读它:
QFile文件( file . dat );file . open(QIODevice:ReadOnly);(文件)中的QDataStreamQString字符串;qint 32 a;在str a中;这个代码没什么好说的。唯一需要注意的是,必须按照书写的顺序读出数据。也就是说,必须预先定义程序数据写入的顺序。在这个例子中,我们先写一个字符串,然后是一个数字,所以先读出字符串,然后是数字。如果顺序颠倒,程序的行为是不确定的,严重时程序会直接崩溃。
因为二进制流是纯字节数据,问题是如果不同版本的程序用不同的方式读取(前面提到Qt保证了读写内容的一致性,但不能保证不同Qt版本之间的一致性),数据就会出错。因此,我们必须提供一种机制来确保不同版本之间的一致性。通常,我们会使用下面的代码来编写:
QFile文件( file . dat );file . open(QIODevice:write only);QDataStream out(文件);//写出幻数和版本out(quint 32)0x a 0 b 0 c 0d 0;out(qint 32)123;out . set version(qdata stream:Qt _ 4 _ 0);//将数据写出lots _ of _ interesting _ data这里,我们添加了两行代码:
out(quint 32)0x a 0 b 0 c 0d 0;
用来写幻数。所谓幻数,是二进制输出中常用的一种技术。二进制格式不可读,通常有相同的后缀(比如dat),所以我们分不清两个二进制文件哪个合法。所以我们定义的二进制格式通常有一个幻数,用来标识文件的合法性。本例中,我们在文件开头写0xA0B0C0D0,读取时先检查这个数是否为0xA0B0C0D0。如果不是,则文件不是可识别的格式,因此没有必要继续读取。一般二进制文件都会有这样一个幻数。比如Java类文件的幻数是0xCAFEBABE,可以用二进制查看器查看。幻数是一个32位无符号整数,所以我们用quint32得到一个平台无关的32位无符号整数。
下一行,
out(qint 32)123;
是标识文件的版本。我们用幻数来识别文件的类型,从而判断文件是否合法。然而,文件的不同版本之间可能存在差异:我们可能在第一个版本中保存整数,而在第二个版本中保存字符串。为了识别不同的版本,我们只能将版本写入文件。比如现在我们的版本是123。
下面一行是关于版本的:
out . set version(qdata stream:Qt _ 4 _ 8);上面这句话就是文件的版本号。但是,不同版本的Qt可能会有不同的解读。这样我们就要指定Qt应该按照哪个版本来读。这里,我们指定以Qt 4.8格式读取内容。
当我们以这种方式编写文件时,我们需要在读取它时添加一系列判断:
QFile文件( file . dat );file . open(QIODevice:ReadOnly);(文件)中的QDataStream//检查幻数quint32 magic在魔术中;如果(魔法!=0x a 0 b 0 c 0d 0){ return BAD _ FILE _ FORMAT;}//检查版本qint32版本;在版本中;if(版本100){ return BAD _ FILE _ TOO _ OLD;} if(123版){ return BAD _ FILE _ TOO _ NEW} if(version=110){ in . set version(qdata stream:Qt _ 3 _ 2);} else { in . set version(qdata stream:Qt _ 4 _ 0);}//读取lots _ of _ interesting _ data中的数据;if(版本=120){ in data _ new _ in _ version _ 1 _ 2;}在other _ interesting _ data这个代码是根据前面的解释执行的。首先,读取幻数,检查文件是否合法。如果合法,不支持读取文件版本:小于100或大于123。如果在支持的版本范围内(100=version=123),则小于等于110时以Qt_3_2格式读取,否则以Qt_4_0格式读取。设置这些参数后,开始读取数据。
至此,我们已经介绍了QDataStream的相关内容。那么,既然QIODevice提供了read()和readLine()等函数,为什么还会有QDataStream呢?QDataStream和QIODevice有什么区别?不同的是,QDataStream提供了流的形式,性能一般比直接调用原API要好。让我们通过下面的代码来看看流的形式是什么:
QFile文件( file . dat );file . open(QIODevice:read write);QDataStream流(文件);QString str=答案是42 ;QString strout流字符串;file . flush();河流冲出;在这段代码中,我们首先将数据写入文件,然后将数据读出。有什么问题吗?跑完之后你会发现strout其实是空的。你为什么不读它?我们不是已经加了file . flush();声明?原因不是文件写没写,而是我们在用“流”。所谓流量,就像水流一样,它的光标会随着输出向后移动。当使用操作符输出时,光标已经到达流的末尾。这个时候,你可以再读,当然什么也读不出来。所以你需要在输出后将光标重置到0的位置,然后才能继续阅读。具体代码片段如下:
流字符串;stream . device()-seek(0);河流冲出;
郑重声明:本文由网友发布,不代表盛行IT的观点,版权归原作者所有,仅为传播更多信息之目的,如有侵权请联系,我们将第一时间修改或删除,多谢。