天天看點

Python資料處理方式1. pickle、cPickle方法2.QDataStream方法3.QTextStream方法

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,我們需要注意寫入和讀取的順序要統一,如下例所示:

例1:

#_*_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_3

s << 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 >> x

Reads 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簡介

QTextStream的readLine()方法,會自動的将trailing end-of-line characters('\n'或"\r\n")删掉,是以無需調用trimmed()方法。如果test stream已經到了檔案的末尾,會傳回空的QString,可以用atEnd()來檢測是否到了檔案末尾。

QTextStream()的輸入必須是文本格式,數字、布爾型以及QString型可以通過<<被正确處理,但其他類型的資料必須被轉化為文本格式