1. pickle、cPickle方法
1.1 pickle简介
pickle和cPickle模块是Python提供的用来序列化和反序列化的模块,可以将Python的数据结构转化为字节流(byte stream),其中cPickle是pickle的C语言实现,因此运行速度上会比pickle运行的快的多。但cPickle并不支持类Pickler() and Unpickler()的子类,不过平常使用中很少会用到这功能,因此pickle和cPickle差别不大,并且cPickle可以提供更快的运行速度。
pickle序列化后的字节流类型是python特有的,因此不可以被其他语言的反序列化;同样也不能反序列化其他语言序列化后的东西
pickle的data stream现在有三种格式:
Protocol version 0 | 序列化后为ASCII格式,兼容以前的格式 |
Protocol version 1 | 序列化后为二进制,兼容以前的格式 |
Protocol version 2 | 序列化后为二进制,提供了对Python新式类更有效的序列化 |
如果没有指定protocol,则会默认使用protocol 0。如果protocol被指定为小于0的或者HIGHEST_PROTOCOL,则会使用当前可用的最高版本。建议使用二进制的格式,可以通过指定protocl>0来选择
并不是所有的类型都支持序列化的,以下的类型是支持序列化的:
- 所有Python支持的 原生类型 : 布尔, 整数, 浮点数, 复数, 字符串, bytes(字节串)对象,
字节数组, 以及 None. - 由任何原生类型组成的列表,元组,字典和集合。
- 由任何原生类型组成的列表,元组,字典和集合组成的列表,元组,字典和集合(可以一直嵌套下去,直至Python支持的最大递归层数).
- 函数,类,和类的实例(带警告)。
1.2 pickle使用方法
为了序列化一个object hierarchy,你必须先创建一个pickler,可以通过pickle.dump()来实现;同样要想反序列化,你也必须先创建一个unpickler,可以通过pickle.load()来实现
pickle.HIGHEST_PROTOCOL
可以获得可用的最高版本,这个返回值可以作为protocol。
pickle.dump(obj,file[,protocol])
将obj序列化到file文件中,protocol参数使用如上所示。
file必须有一个write()方法并且可以接受字符串参数。例如StringIO等
pickle.load(file)
从file中读取字符串,并将其作为pickle类型进行反序列化,重新构造并返回被序列化的object hierarchy
这个file必须有接受Integer参数的read()方法和没有参数的readline()方法,可选的类型与pickle.dump的类似。该方法会自动检测到这个文件是ASCII还是二进制格式
例1:
import cPickle t={1:"wo ai",2:('a','b','c'),3:{'a':1,'b':2,'c':3}} fn=open('/home/aixiao/new.file','wb') cPickle.dump(t, fn, 2) fn.close() fn=open('/home/aixiao/new.file','rb') out=cPickle.load(fn) print out
输出:
{1:"wo ai",2:('a','b','c'),3:{'a':1,'b':2,'c':3}}
pickle.dumps(obj[,protocol])
与pickle.dump类似,不过会将序列化后的数据流以字符串形式返回,而不是将数据流写入文件中
pickle.loads(string)
读取pickle.dump返回的字符串,反序列化,然后返回object hierarey
例1:
before={1:"wo ai",2:('a','b','c'),3:{'a':1,'b':2,'c':3}} str=cPickle.dumps(before, cPickle.HIGHEST_PROTOCOL) print type(str) after=cPickle.loads(str) print 'after='+repr(after) if before is after: print 'before is after' elif before ==after: print 'before == after'
结果:
<type 'str'> after={1: 'wo ai', 2: ('a', 'b', 'c'), 3: {'a': 1, 'c': 3, 'b': 2}} before == after
结果输出
before == after
可以看出,经过反序列化重新生成的字典after只是对以前字典的一个完美复制
参考资料:
http://woodpecker.org.cn/diveintopython3/serializing.html
《Rapid GUI Programming wiht Python and Qt》
2.QDataStream方法
2.1 QDataStream简介
- QDataStream是Qt提供编码过后的二进制的data stream,与平台完全无关,你完全可以在windows下生成一个data stream然后到不同架构不同系统的平台下读取。
- QDataStream可以读写Python和PyQt中的很多数据类型,包括PyQt中的QImage、QColor等,具体可以查看Qt文档的Serializing Qt Data Types。
- 数据都是以特定的格式写入QDataStream中的,因此写入的格式随数据类型的不同而不同。
- QDataStream必须有写入和写出的媒介,一般以QIODeviece为这个媒介,可以在QDataStream的构造函数中指定QIODevice,也可以通过setDevice()在适当的地方指定
- QDataStream的数据格式一直在演化,因此读写数据的时候一定要看清QDataStream的版本,读和写一定要用相同版本的QDataStream。我们可以通过setVersion的办法来设置QDataStream的版本
- PyQt并不知道我们要写入QDataStream的int和long到底都多长,因此我们必须使用writeInt()和writeUInt()方法,我们通过8,16和32来指定我们要存的int 和long要占多少bits。对于浮点型,QDataStream提供了readDouble()和writeDouble(),浮点型会被存为64位IEEE-754格式。
- 因为有时候文件文字并不能唯一的标识一个文件,QDataStream中我们设置了一个Magci Number和一个file version。这个Magic Number一般放在QDataStream的最开始唯一的标识一个文件,是作为一个32位的整型存放,因为Int编码后的格式是统一的。file
version用来标识文件的版本,也是一个32位整型。同一个文件可能经过多次修改,因此其file version会发生改变,不过文件还是那个文件,因此其Magic number不改变 - 使用QDataStream,我们需要注意写入和读取的顺序要统一,如下例所示:
#_*_encoding:gb2312 _*_ from PyQt4.QtGui import * from PyQt4.QtCore import * import sys class Data(): def __init__(self,filename): error=None fh=None self.__fname=filename self.MAGIC_NUMBER=0x11223344#定义magic number和file version self.FILE_VERSION=125 self.str=QString(u"我爱小宇") try: fh=QFile(self.__fname) if not fh.open(QIODevice.WriteOnly): raise IOError,unicode(fh.errorString()) stream=QDataStream(fh) stream.writeInt32(self.MAGIC_NUMBER) stream.writeInt32(self.FILE_VERSION) stream<<self.str stream.writeInt16(123) stream.setVersion(QDataStream.Qt_4_2) except (IOError,OSError),e: error = "Failed to save:%s" % e finally: if fh is not None: fh.close() if error is not None: print error else: print "Save to file %s success...." % self.__fname def loadFile(self): error=None fh=None try: fh=QFile(self.__fname) if not fh.open(QIODevice.ReadOnly): raise IOError,unicode(fh.errorString()) stream=QDataStream(fh) magic=stream.readInt32() if magic !=self.MAGIC_NUMBER: raise IOError,"unrecognized file" version=stream.readInt32() if version<self.FILE_VERSION: raise IOError,"Old and unreadable file format" if version>self.FILE_VERSION: raise IOError,"New and unreadable file format" stream.setVersion(QDataStream.Qt_4_2) while not stream.atEnd(): self.data=QString() stream>>self.data self.num=stream.readInt16() except (IOError,OSError),e: error="Load file failed:%s" % e finally: if fh is not None: fh.close() if error != None: print "Load file failed:%s" % e else: print "Load file %s success..." % self.__fname print "Str:%s Num:%d" % (self.data,self.num) data=Data("/home/aixiao/newfile.txt") data.loadFile()
运行结果:
Save to file /home/aixiao/newfile.txt success.... Load file /home/aixiao/newfile.txt success... Str:我爱小宇 Num:123
附:QDataStream常用函数介绍
s.atEnd() Returns True if the end of QDataStream s has been reached s.setVersion(v) Sets QDataStream s’s version to v, where v is one of Qt_1_0,
Qt_2_0,…, Qt_4_2, or Qt_4_3s << x Writes object x to QDataStream s; x can be of type QBrush,
QColor, QDate, QDateTime, QFont, QIcon, QImage, QMatrix,
QPainterPath, QPen, QPixmap, QSize, QString, QVariant, etc.s.readBool() Reads a bool from QDataStream s s.readDouble() Reads a float from QDataStream s s.readInt16() Reads a 16-bit int from QDataStream s. There is also a s.readInt32() Reads a 32-bit int from QDataStream s. There is also a readUInt32() method. s.readInt64() Reads a 64-bit long from QDataStream s. There is also a readUInt64() method. x =QString()
s >> xReads object x from QDataStream s; x must already exist (so
that the data stream knows what data type to read), and can be
any of the types writable by <<s.writeBool(b) Writes bool b to QDataStream s s.writeInt16(i) Writes int i as a 16-bit int to QDataStream s. There is also a writeUInt16()
method.s.writeInt32(i) s.writeInt64(l) Writes long l as a 64-bit int to QDataStream s. There is also
a writeUInt64() method.
3.QTextStream方法
3.1 QTextStream简介
stream已经到了文件的末尾,会返回空的QString,可以用atEnd()来检测是否到了文件末尾。