Python基礎-19文件讀寫

19. 文件讀寫

19.1 文件操作

? ? 數據持久化,是將程序中的對象以數據的方式保存到磁盤上,在程序下次運行時,可以將數據從磁盤上恢復到內存中。數據持久化的方式有很多,而最為常見的方式是將數據以文件的形式保存。在Python中,可以通過內置函數的方法進行文件的讀、寫、刪除等操作。

19.1.1 文件的基本操作

? ? 文件的基本操作比較多,如創建、刪除、修改權限、寫入、讀取等等。

  • 刪除、修改權限:作用于文件本身,屬于系統級操作
  • 讀取、寫入:是文件最常用的操作,作用于文件內容,屬于應用級操作

? ? 文件的系統級操作,一般使用Python中的os、sys等模塊。

19.1.2 讀寫文件的一般步驟

? ? 讀寫文件一般常分為3步,每一步可使用相應的方法

  • 1.打開文件:使用open方法,返回一個文件對象
  • 2.具體的讀寫操作:使用該文件對象的read/write等方法
  • 3.關閉文件:使用該文件對象的close方法

一個文件,必須在打開之后才可以對其進行相應的操作,并在操作完成均完成進行關閉。

19.1.2.1 打開文件

? ? 打開文件是讀寫操作的第一步,其方法open的具體定義如下所示:

open(file, mode='r', buffering=None, encoding=None, errors=None, newline=None, closefd=True)

? ? 比較關鍵的參數如下所示:

  • file:打開的文件名,屬于字符串類型,但如果文件名含有特殊字符,需要進行轉義。
  • mode:打開文件的方式,如只讀、只寫、讀寫、二進制等等產,默認為只讀。
  • encoding:如直接保存為文件文本,需要指定編碼格式,不然會造成讀取文件文件出現亂碼

? ? mode的詳細介紹如下所示:

mode 含義
r 只讀,但文件必須存在
w 只寫,如果文件已經存在,則覆蓋,不存在,則重新創建
a 以只寫的文件打開文件,并在文件后追加內容,如果文件不存在,則創建新文件
b 以二進制形式打開,不能單獨使用
+ 以讀寫形式打開文件, 不能單獨使用
r+ 以讀寫形式打開文件,文件必須存在,當寫入時,會清空原內容
w+ 以讀寫形式打開文件,文件不存在則創建文件,如已經存在,當寫入時,會清空原內容
a+ 以讀寫形式打開文件,文件不存在則創建文件,如已經存在,當寫入時,在文件后追加原內容

以上僅為常見的一些模式,實際應用還可使用組合模式,即同時使用多種模式來操作文件,如rb、wb、wb+、ab等

? ? 另外根據操作系統的不同,又可以分為文本模式二進制模式,其主要區別如下所示:

  • 在Windows系統中,文本模式下Windows平臺的末尾換行符為\r\n,在讀取時轉換為\n,而在寫入時又將\n轉換為\r\n。這種隱藏的行為對于文本文件是沒有問題的,但如果以文本模式打開二進制數據文件(如圖片、EXE程序等)則會發生問題,因改變了文件的具體內容。
  • 在Unix/Linux系統中,末尾換行符為\n,因此兩者沒有區別
19.1.2.2 具體讀寫操作

? ? 通過open方法得到文件對象后,就可以對文件進行操作,常用的方式是讀和寫。

1.讀取文件

? ? 通過調用文件對象的read方法可以獲得文件的內容,示例代碼如下所示:

>>> fo=open(r"C:\Surpass\a.txt","r")
>>> s=fo.read()
>>> s

? ? 打開文件后,文件對象fo中的read方法,會將文件的全部內容一次性讀取到內存中。

2.寫入文件

? ? 將字符串寫入文件,可以調用文件對象的write方法,示例代碼如下所示:

>>> fo=open(r"C:\Surpass\a.txt","w")
>>> fo.write("Surpass")

如果文件是以二進制形式打開,則只能以二進制形式寫入數據

>>> fo=open(r"C:\Surpass\a.txt","wb")
>>> fo.write(b"Surpass")
19.1.2.3 關閉文件

? ? 直接使用文件對象的close方法即可。在打開文件并全部操作完之后,需要及時關閉。否則會導致其他操作出錯,如刪除、移動等,則提示文件正在使用。

19.1.3 文件對象方法

? ? 常見的文件對象方法如下所示:

方法 描述
read(size) 讀取指定size的字節數據,然后作為字符串或bytes對象返回,size為可選參數,如未指定,則默認文件所有內容
readline() 讀取一行,并在字符串末尾留下換行符\n,如果到文件尾,則返回空字符串
readlines() 讀取所有行,并保存至列表中,每個元素代表一行,類似于list(fo)
writer(string) 將string寫入到文件中,返回寫入的字符數,如果以二進制模式,則需要將string轉換為bytes對象
tell() 返回文件對象當前所在位置,從文件開頭開始計算字節數
seek(offset,from_what) 改變文件對象所處的位置。offset是相對參考位置的偏移量,from_what表示參考位置,0-文件頭,默認;1-當前位置;2-文件尾

19.1.4 文件對象迭代器

? ? 文件對象本身也是一個迭代器,可以與for循環配合進行文件的讀取。示例如下所示:

>>> f=open("a.txt","wb+")
>>> f.write(b"name is Surpass,age is 28\n")
25
>>> f.write(b"I am learning Python")
20
>>> f.close()
>>> f=open("a.txt","r+")
>>> for content in f:
...     print(content)
name is Surpass,age is 28
I am learning Python
>>> f.close()

? ? 在for循環中,每循環一次,相當于調用了一次readline方法。

19.1.5 使用with簡化文件操作

? ? 通過以上你會發現,每次使用文件操作,都需要3個步驟。那有沒有簡便的辦法來簡化這些操作了?Python內置了with語句,使用其可以簡化這種寫法,在調用完成之后,with語句會自動關閉。其語法格式如下所示:

with 表達式 as 變量:
    doSomething

針對文件操作而言,表達式就是open函數,as后面的變量就是open返回的文件對象。

? ? 示例代碼如下所示:

import os

filePath=os.getcwd()
filename="a.txt"

with open(os.path.join(filePath,filename),"wb+") as fo:
    try:
         fo.write(b"name is Surpass,age is 28\n")
         fo.write(b"I am learning Python")
    except Exception as ex:
        print(f"write error\{ex}")
        
with open(os.path.join(filePath,filename),"r") as fo:
    for content in fo:
        print(content)

19.1.6 字符串與二進制的轉化

? ? 在處理文件操作時,常用的做法是以二進制形式保存,以文件方式使用。一是二進制文件更小,便于網絡傳輸和存儲,另外也可以避免保存與讀取編碼不同造成的亂碼情況。

19.1.6.1 將字符串轉換為二進制數

? ? bytes定義格式如下所示:

string, encoding[, errors]

? ? 示例代碼如下所示:

>>> tempA=b"name is Surpass,age is 28"
>>> tempB=bytes("name is Surpass,age is 28","utf8") # 使用utf8編碼
>>> print(f"{tempA}\n{tempB}")
b'name is Surpass,age is 28'
b'name is Surpass,age is 28'
19.1.6.2 將二進制數轉換為字符串

? ? 如果將二進制數轉換為字符串,可以調用二進制對象的decode方法,并傳入指定的解碼格式,示例如下所示:

>>> tempB=bytes("我愛中國,I love China","gb2312")
>>> print(f"{tempB}\n{tempB.decode('utf8')}\n{tempB.decode()}")
Traceback (most recent call last):
  File "<input>", line 1, in <module>
UnicodeDecodeError: 'utf-8' codec can't decode byte 0xce in position 0: invalid continuation byte

? ? 程序報錯了,這個問題仔細看看,就知道原因所在了,編碼使用gb2312,解碼使用了utf8。因此在做轉換時,需要避免這種情況發生,

>>> tempB=bytes("我愛中國,I love China","gb2312")
>>> print(f"{tempB}\n{tempB.decode('gb2312')}")
b'\xce\xd2\xb0\xae\xd6\xd0\xb9\xfa\xa3\xacI love China'
我愛中國,I love China

? ? Windows平臺與Linux平臺編碼解碼是有區別的,主要如下所示:

  • 在Linux平臺中,生成的文件默認編碼是utf8格式,所以解碼需要指定解碼格式應為utf8
  • 在Windows平臺中,中文操作系統生成文件默認為gb2312/gbk格式,所以解碼需要指定為相應的編碼格式才能正常解碼

為避免因操作系統不同,因此在轉換時需要顯式指定相應的編碼和解碼格式

19.2 json讀寫

? ? 在日常種類接口測試中,會經常處理JSON格式的請求報文和響應報文等,平時用得最多的也是Python自帶的json包,其提供了4個方法dumpsdumploadsload

? ? 1、JSON不能存儲每一種Python值,僅能存儲以下數據類型的傳下

  • 字符串
  • 整形
  • 浮點型
  • 布爾型
  • 列表
  • 字典
  • NoneType

? ? 2、JSON不能表示Python對象,如File對象、CSV Reader、Regex對象等

19.2.1 查看json的使用方法

import json
print(json.__all__)

輸出結果為:

['dump', 'dumps', 'load', 'loads', 'JSONDecoder', 'JSONDecodeError', 'JSONEncoder']

19.2.2 json 讀取

? ? json包常用的讀取方法為loadsload

loads:可理解為load string,其功能是將json格式的字符串轉換為Python數據類型(字典)
load:讀取json文件,將轉換為Python類型

? ? 以下分別介紹其用法

19.2.2.1 json.loads

loads常用用法如下所示:

json.loads(str,encoding='utf8')

示例如下所示:

import json

jsonStr="""{
    "book":"json in action",
    "author":"Surpassme",
    "isbn":961839721541,
    "中文名":"JSON實戰"
}"""

print(f"jsonStr type is {type(jsonStr)}")
if isinstance(jsonStr,(str,)):
    result=json.loads(jsonStr,encoding="utf8")
    print(f"輸出的json\n{result}")
else:
    print(f"傳入的字符類型{type(jsonStr)},不是字符串")

輸出結果

jsonStr type is <class 'str'>
輸出的json
{'book': 'json in action', 'author': 'Surpassme', 'isbn': 961839721541, '中文名': 'JSON實戰'}

需要注意兩點:
1、傳入的數據一定要是字符串格式,如果傳入字典則會出錯
2、建議增加字符串編碼格式,防止出現亂碼

19.2.2.2 json.load

load常用用法如下所示:

json.load(jsonfile)

示例如下所示:

import json
import os

def ReadJsonFile(path,strEncode="utf8"):
    try:
        with open(path,"r",encoding=strEncode) as fr:
            return json.load(fr)
    except Exception as ex:
        raise ex

if __name__=="__main__":
    jsonFile=os.getcwd()+"\\jsonfile.json"
    data=ReadJsonFile(jsonFile)
    print(f"data is\n{data}")

輸出結果

data is
{'book': 'json in action', 'author': 'Surpassme', 'isbn': 961839721541, '中文名': 'JSON實戰'}

19.2.3 json保存

? ? json包常用的讀取方法為dumpsdump

dumps:可理解為dump string,其功能是將Python數據類型將轉換為json格式的字符串
dump:將Pyhon數據保存為json文件

19.2.3.1 dumps

dumps常用用法如下所示:

json.dumps(obj,ensure_ascii=True,indent=None)

  • ensure_ascii:輸出字符串是否采用ascii編碼,如果有中文,需要使用utf8編碼
  • indent:輸出美化功能,一般為正數才有效

示例如下所示:

import json

jsonStr={
    "book":"json in action",
    "author":"Surpassme",
    "isbn":961839721541,
    "中文名":"JSON實戰"
}
result=json.dumps(jsonStr,ensure_ascii=False,indent=1)
print(result)

運行結果如下所示:

{
 "book": "json in action",
 "author": "Surpassme",
 "isbn": 961839721541,
 "中文名": "JSON實戰"
}
19.2.3.2 dump

dump常用用法如下所示:

json.dump(obj,file,ensure_ascii=True,indent=None)

示例如下所示:

import json
def SavaAsJsonFile(path,data,strEncode="utf8",ensure_ascii=False,indent=None):
    try:
        with open(path,"a",encoding=strEncode) as fw:
            return json.dump(data,fw,ensure_ascii=ensure_ascii,indent=indent)
    except Exception as ex:
        raise ex
    
if __name__=="__main__":
     jsonStr={
        "book":"json in action",
        "author":"Surpassme",
        "isbn":961839721541,
        "中文名":"JSON實戰"
     }
     path=os.getcwd()+"\\jsonfile.json"
     SavaAsJsonFile(path,jsonStr,indent=1)

運行結果如下所示:

{
 "book": "json in action",
 "author": "Surpassme",
 "isbn": 961839721541,
 "中文名": "JSON實戰"
}

19.3 csv讀寫

? ? csv(Comma-Separated Values)一般是特指以逗號做為分隔符的文本文件。因使用簡單方便,平時在測試過程也會經常用到該類型文件。今天就來學習一下在Python中如何處理csv文件。

19.3.1 CSV讀取

19.3.1.1 常規讀取

讀取CSV文件常用的步驟為,創建一個CSV文件對象,打開文件進行讀取

  • CSV文件如下所示:
190201SampleCSVFile.jpg
  • 示例代碼如下所示:
import csv
import os

def ReadCSVFile(path=os.getcwd(),fileName="test.csv",fileEncode="utf8"):
    csvFilePath=path+"\\"+fileName
    dataValue=[]
    if os.path.exists(csvFilePath) and os.path.isfile(csvFilePath):
        try:
            with open(csvFilePath,"r",encoding=fileEncode) as fr:
                dataContent=csv.reader(fr)
                for dataRow in dataContent:
                    dataValue.append(dataRow)
        except Exception as ex:
            raise ex
    return dataValue

if __name__=="__main__":
    path=r"C:\Users\Administrator\PycharmProjects\TestProject\PythonIOTest\csvLesson"
    fileName="CSVTestFile.csv"
    data=ReadCSVFile(path=path,fileName=fileName)
    for item in data:
        print(item)
  • 運行結果如下所示:
['ID', 'Department', 'Employees', 'HireDate']
['1', 'Dev', 'Kevin', '2019-10-30']
['2', 'Prd', 'Lily', '2019-10-31']
['3', 'Test', 'Kate', '2019-11-01']
['4', 'Dev', 'Leo', '2019-11-02']
['5', 'Prd', 'Lucy', '2019-11-03']
['6', 'Test', 'Bruce', '2019-11-04']
['7', 'Dev', 'KK', '2019-11-05']
['8', 'Dev', 'Gaga', '2019-11-06']
['9', 'Dev', 'ABC', '2019-11-07']
['10', 'Dev', 'HBO', '2019-11-08']
19.3.1.2 字典形式讀取

? ? 如果CSV文件第一行為標題行,余下全部為數據,則可以采用字典形式進行讀取。 以此種方式讀取時,會默認將第一行(標題)做為Key值,從第二行開始做為數據內容即Value

  • 示例代碼如下所示:
import csv
import os

def ReadFromDict(path=os.getcwd(),fileName="test.csv",fileEncode="utf8"):
    csvFilePath=path+"\\"+fileName
    dataValue=[]
    if os.path.exists(csvFilePath) and os.path.isfile(csvFilePath):
        try:
            with open(csvFilePath,"r",encoding=fileEncode) as fr:
                dataContent=csv.DictReader(fr)
                headers=dataContent.fieldnames
                next(dataContent)
                for dataRow in dataContent:
                    dataValue.append(dataRow)
        except Exception as ex:
            raise ex
    return dataValue,headers

if __name__=="__main__":
    path=r"C:\Users\Administrator\PycharmProjects\TestProject\PythonIOTest\csvLesson"
    fileName="CSVTestFile.csv"
    data,headers=ReadFromDict(path=path,fileName=fileName)
    print(f"header is {headers}")
    for item in data:
        outStr=f'ID is {item.setdefault("ID","Exception")},Employee name is {item.setdefault("Employees", "Exception")} \
           employees\'s department {item.setdefault("Department","Exception")}'
        print(outStr)
  • 運行結果如下所示:
header is ['ID', 'Department', 'Employees', 'HireDate']
ID is 1,Employee name is Kevin            employees's department Dev
ID is 2,Employee name is Lily            employees's department Prd
ID is 3,Employee name is Kate            employees's department Test
ID is 4,Employee name is Leo            employees's department Dev
ID is 5,Employee name is Lucy            employees's department Prd
ID is 6,Employee name is Bruce            employees's department Test
ID is 7,Employee name is KK            employees's department Dev
ID is 8,Employee name is Gaga            employees's department Dev
ID is 9,Employee name is ABC            employees's department Dev
ID is 10,Employee name is HBO            employees's department Dev

19.3.2 CSV寫入

19.3.2.1 常規寫入

讀取CSV文件常用的步驟為,創建一個CSV文件對象,打開文件進行寫入

  • 示例代碼如下所示:
import csv
import os

def ReadCSVFile(path=os.getcwd(),fileName="test.csv",fileEncode="utf8"):
    csvFilePath=path+"\\"+fileName
    dataValue=[]
    if os.path.exists(csvFilePath) and os.path.isfile(csvFilePath):
        try:
            with open(csvFilePath,"r",encoding=fileEncode) as fr:
                dataContent=csv.reader(fr)
                for dataRow in dataContent:
                    dataValue.append(dataRow)
        except Exception as ex:
            raise ex
    return dataValue

def SaveCSVFile(path=os.getcwd(),fileName="testSave.csv",fileEncode="utf8",content=""):
    csvFilePath=path+"\\"+fileName
    if os.path.exists(path) and os.path.isdir(path):
        try:
            with open(csvFilePath,'w+',encoding=fileEncode,newline="") as fw:
               dataObj=csv.writer(fw)
               for item in content:
                   dataObj.writerow(item)
        except Exception as ex:
            raise ex
if __name__=="__main__":
    path=r"C:\Users\Administrator\PycharmProjects\TestProject\PythonIOTest\csvLesson"
    print("Test save file as csv file")
    data=[
           ['ID', 'Department', 'Employees', 'HireDate'],
           ['1', 'Dev', 'Kevin', '2019-10-30'],
           ['2', 'Prd', 'Lily', '2019-10-31'], 
           ['3', 'Test', 'Kate', '2019-11-01'], 
           ['4', 'Dev', 'Leo', '2019-11-02'], 
           ['5', 'Prd', 'Lucy', '2019-11-03']
    ]
    SaveCSVFile(path=path,content=data)
    dataFromSaveFile=ReadCSVFile(path=path,fileName="testSave.csv")
    for item in dataFromSaveFile:
        print(item)

1、如果保存的CSV文件出現空白行,則在with open(...,newline="")增加參數newline=""
2、CSV.Writer中的方法writerow()方法接受一個列表參數。列表中的每個詞,放在輸出的CSV文件中的一個單元格中。writerow()函數的返回值,是寫入文件中這一行的字符數(包含換行符)

  • 運行結果如下所示:
Test save file as csv file
['ID', 'Department', 'Employees', 'HireDate']
['1', 'Dev', 'Kevin', '2019-10-30']
['2', 'Prd', 'Lily', '2019-10-31']
['3', 'Test', 'Kate', '2019-11-01']
['4', 'Dev', 'Leo', '2019-11-02']
['5', 'Prd', 'Lucy', '2019-11-03']
19.3.2.2 字典形式寫入

? ? 如果我們要創建帶有標題和數據的CSV文件,則可以采用以字典形式進行保存文件。

  • 示例代碼如下所示:
import csv
import os

def ReadFromDict(path=os.getcwd(),fileName="test.csv",fileEncode="utf8"):
    csvFilePath=path+"\\"+fileName
    dataValue=[]
    if os.path.exists(csvFilePath) and os.path.isfile(csvFilePath):
        try:
            with open(csvFilePath,"r",encoding=fileEncode) as fr:
                dataContent=csv.DictReader(fr)
                headers=dataContent.fieldnames
                next(dataContent)
                for dataRow in dataContent:
                    dataValue.append(dataRow)
        except Exception as ex:
            raise ex
    return dataValue,headers

def SaveCSVFileUseDict(path=os.getcwd(),fileName="testSave.csv",fileEncode="utf8",headers="",content=""):
    csvFilePath=path+"\\"+fileName
    if os.path.exists(path) and os.path.isdir(path):
        try:
            with open(csvFilePath,'w+',encoding=fileEncode,newline="") as fw:
               dataObj=csv.DictWriter(fw,fieldnames=headers)
               dataObj.writeheader()
               for item in content:
                   dataObj.writerow(item)
        except Exception as ex:
            raise ex


if __name__=="__main__":
    path=r"C:\Users\Administrator\PycharmProjects\TestProject\PythonIOTest\csvLesson"
    fileName="CSVTestFile.csv"
    print("Test save file as csv file")
    headers={"ID", "Name", "Author", "ISBN"}
    data=[
        {"ID":"1","Name":"Python基礎教程","Author":"Surpassme","ISBN":1088021365},
        {"ID":"2","Name":"Java基礎教程","Author":"Surpassme","ISBN":2088021365},
        {"ID":"3","Name":"C#基礎教程","Author":"Kevin","ISBN":3088021365},
    ]
    SaveCSVFileUseDict(path=path,headers=headers,content=data)
    dataFromSaveFile,headers=ReadFromDict(path=path,fileName="testSave.csv")
    print(f"header is {headers}")
    for item in dataFromSaveFile:
        print(item)

以字典形式保存時,需要注意標題即為字典的Key值

  • 運行結果如下所示:
Test save file as csv file
header is ['ID', 'Name', 'ISBN', 'Author']
OrderedDict([('ID', '2'), ('Name', 'Java基礎教程'), ('ISBN', '2088021365'), ('Author', 'Surpassme')])
OrderedDict([('ID', '3'), ('Name', 'C#基礎教程'), ('ISBN', '3088021365'), ('Author', 'Kevin')])
19.3.2.3 自定義分隔符和終止符

? ? 如果希望可以自定義分隔符(如Tab),希望有兩倍行距,則可以使用delimiter和lineterminator關鍵字參數。

  • 示例代碼如下所示:
import csv
import os

def SaveCSVFile(path=os.getcwd(),fileName="test.csv",content="",delimiter=",",lineterminator="\n",fileEncoding="utf8"):
    csvFilePath=path+"\\"+fileName
    if os.path.exists(path) and os.path.isdir(path):
        try:
           with open(csvFilePath,"w+",encoding=fileEncoding,newline="") as fw:
               dataObj=csv.writer(fw,delimiter=delimiter,lineterminator=lineterminator)
               for item in content:
                   dataObj.writerow(item)
        except Exception as ex:
            raise ex

if __name__=="__main__":
    path=r"C:\Users\Surpass\PycharmProjects\PythonIOTest\csvLesson"
    print(f"Test save csv file")
    data=[
           ['ID', 'Department', 'Employees', 'HireDate'],
           ['1', 'Dev', 'Kevin', '2019-10-30'],
           ['2', 'Prd', 'Lily', '2019-10-31'],
           ['3', 'Test', 'Kate', '2019-11-01'],
           ['4', 'Dev', 'Leo', '2019-11-02'],
           ['5', 'Prd', 'Lucy', '2019-11-03']
    ]
    SaveCSVFile(path=path,content=data,delimiter="\t",lineterminator="\n\n")
  • 運行結果如下所示:
190202自定義分隔符和終止符.jpg

19.3.3 示例項目

? ? 假設現在有一個任務,從一個文件夾中刪除所有CSV文件的第一行。主要方法如下所示:

  • 依次逐個打開CSV文件,刪除第一行數據,再保存
  • 在網上找找有沒有相應的工具
  • 自己使用代碼編寫工具

? ? 今天我們就來嘗試用Python來解決該任務。先來分析一下,使用代碼需要解決的問題點有哪些

  • 過濾到文件為CSV類型的文件
  • 讀取每個文件的全部內容
  • 刪除CSV文件的第一行,并保存為CSV文件

在使用工具或代碼來修改文件時,需要將數據或文件進行備份

詳細示例如下所示:

import csv
import os
import shutil

def GetCSVFileList(path,extName=".csv"):
    """
    獲取CSV文件列表
    """
    csvFileList=[]
    for r,s,fs in os.walk(path):
        for csvFile in fs:
            if os.path.isfile(os.path.join(r,csvFile)) and os.path.splitext(os.path.join(r,csvFile))[-1] in extName:
                csvFileList.append(os.path.join(r,csvFile))
    return csvFileList

def ReadCSVFile(csvFileList,encoding="utf8"):
    """讀取CSV文件"""
    csvRows=[]
    for csvFile in csvFileList:
        csvFilePath=(os.path.split(csvFile))[0]+"\\headerRemoved\\"+os.path.basename(csvFile)
        try:
            with open(csvFile,"r",encoding=encoding) as fr:
              csvObj=csv.reader(fr)
              for row in csvObj:
                  if csvObj.line_num==1:
                      continue
                  csvRows.append(row)
              WriterCSVFile(csvFilePath,csvRows) 
              csvRows.clear()  
        except Exception as ex:
            raise ex

def WriterCSVFile(path,data,encoding="utf8"):
    """保存CSV文件"""
    try:
        with open(path,"w+",encoding=encoding,newline="") as fw:
             csvWriteObj=csv.writer(fw)
             for row in data:
                 csvWriteObj.writerow(row)
    except Exception as ex:
        raise ex

def SaveAsDirectory(path,dirName):
    """創建另存文件夾"""
    tempDir=path+"\\"+dirName
    try:
        if os.path.isdir(tempDir) and os.path.exists(tempDir):
           shutil.rmtree(tempDir)
           os.makedirs(tempDir,exist_ok=True)
        else:
           os.makedirs(tempDir,exist_ok=True)
    except Exception as ex:
        raise ex

if __name__=="__main__":
    path=r"C:\Users\Surpass\PycharmProjects\PythonIOTest\csvLesson\CSVFile"
    SaveAsDirectory(path,"headerRemoved")
    csvFiles=GetCSVFileList(path)
    ReadCSVFile(csvFiles)

最終的運行效果如下所示:

190203項目示意圖.jpg

19.4 YAML讀寫

19.4.1 YAML簡介

? ? YAML是YAML Ain't Markup Language的遞歸縮寫,意思其實是:"Yet Another Markup Language"。YAML 的語法和其他高級語言類似,并且可以簡單表達清單、散列表,標量等數據形態。它使用空白符號縮進和大量依賴外觀的特色,特別適合用來表達或編輯數據結構、各種配置文件、傾印調試內容、文件大綱,其擴展名為.yml.

19.4.2 基本語法

  • 區分大小寫
  • 使用縮進表示層級關系,同層元素左對齊
  • 縮進時不允許使用Tab鍵,只允許使用空格。
  • 縮進的空格數目不重要,只要相同層級的元素左側對齊即可
  • 字串一般不使用引號,但必要的時候可以用引號框住
  • 使用雙引號表示字串時,可用**進行特殊字符轉義
  • #表示注釋

19.4.3 數據類型

  • 對象:鍵值對的集合,又稱為映射(mapping)/ 哈希(hashes) / 字典(dictionary)
  • 數組:一組按次序排列的值,又稱為序列(sequence) / 列表(list)
  • 純量(scalars):單個的、不可再分的值
19.4.3.1 對象
  • 對象通常是鍵值對形式(key: value),冒號后面要加一個空格。示例如下所示:
key: 
    ckey1: cvalue1
    ckey2:  cvalue2
    ckey3:
          cckey1:  ccvalue1
          cckye2:  ccvalue2
    ckey4:  cvalue4

key: {ckey1: cvalue1, ckey2:  cvalue2,ckey3: {cckey1:  ccvalue1, cckye2:  ccvalue2},  ckey4:  cvalue4}
  • 使用?+空格表示復雜鍵,當鍵是一個列表或鍵值表時,就需要使用該符號進行表示。示例如下所示:
?
   - Red
   - Green
   - Blue
:
   - Color

以上等價于

 {[blue, reg, green]: Color}
19.4.3.2 數組

- 開頭的行表示構成一個數組

  • 一維數組
- Red
- Green
- Blue

以上等價于

[ 'Red', 'Green', 'Blue' ]
  • 多維數組
- 
  - Red
  - Green
  - Blue
- 
  - apple
  - tree
  - ocean

以上等價于

[ [ 'Red', 'Green', 'Blue' ], [ 'apple', 'tree', 'ocean' ] ]
  • 復雜結構

對象和數組可以組合成更為復雜的結構,示例如下所示:

Person:
   - sex:
      - man
      - woman
   - color:
        yellow: Asia
        white: Europe
        balck: Africa
country:
    - China
    - American
    - South Korea
    - Russia
City:
    - 
       id:  1
       name: shanghai
    - 
       id: 2
       name: beijing

以上等價于:

{
 Person: [ 
     { 
       sex: [ 'man', 'woman' ] 
     },
     { 
        color: 
           { 
              yellow: 'Asia', 
              white: 'Europe', 
              balck: 'Africa' 
           }
     } 
   ],
 country: [ 'China', 'American', 'South Korea', 'Russia' ],
 City: [
      { 
         id: 1, 
         name: 'shanghai' 
      }, 
      { 
         id: 2, 
         name: 'beijing' 
      }
    ] 
}
19.4.3.3 純量

純量是最基本,不能再分割的值,如下所示:

  • 字符串
  • 布爾值
  • 整數
  • 浮點數
  • Null
  • 時間
  • 日期

示例如下所示:

  • 字符串
str:
  - test str
  - "test \n double " # 可以使用雙引號或者單引號包裹特殊字符,雙引號不會對特殊字符轉義。
  - 'test \n double'
  - line
     newline # 字符串可以拆成多行,每一行會被轉化成一個空格
  - 'testor'' day' # 單引號之中如果還有單引號,必須連續使用兩個單引號轉義。
test: | # 多行字符串可以使用|保留換行符,也可以使用 > 折疊換行
   def
   foo
python: >
   def
   foo
textblock1: |+ # + 表示保留文字塊末尾的換行,- 表示刪除字符串末尾的換行。
   def
   
   foo
   
textblock2: |-
   def 
   
   foo

顯示結果如下所示:

str:
   [ 'test str',
     'test \n double ',
     'test \\n double',
     'line newline',
     'testor\' day' ],
  test: 'def\nfoo\n',
  python: 'def foo  \n',
  textblock1: 'def\n\nfoo\n\n',
  textblock2: 'def \n\nfoo' }
  • 布爾值
isMatch:
   - true # true,True都可以
   - False # false,False都可以

顯示結果如下所示:

isMatch: [ true, false ]
  • 整數與浮點數
intNum:
  - 123
  - 0b11100011
  - 0x12A
floatNum:
  - 123.25
  - 3.1415392e+5

顯示結果如下所示:

intNum: [ 123, 227, 298 ]
floatNum: [ 123.25, 314153.92 ]
  • Null
isNull: ~ # 使用~表示null

顯示結果如下所示:

isNull: null
  • 時間與日期
datetime: 2020-01-19T10:34:30+08:00 # 時間使用ISO 8601格式,時間和日期之間使用T連接,最后使用+代表時區
date: 2020-01-19  # 日期必須使用ISO 8601格式,即yyyy-MM-dd
time: 10:34:30

顯示結果如下所示:

datetime: Sun Jan 19 2020 10:34:30 GMT+0800 (中國標準時間),
date: Sun Jan 19 2020 08:00:00 GMT+0800 (中國標準時間),
time: 38070,

19.4.4 引用

錨點&和別名*,可以用來引用,示例如下所示:

server: &server
   host: 10.68.1.81
   username: root
   password: password
test:
   <<: *server
   datebase: test
dev:
   <<: *server
   database: dev
rel:
   <<: *server
   database: rel

最終顯示的結果如下所示:

{ 
   server: 
     {
         host: '10.68.1.81',
         username: 'root', 
         password: 'password'
     },
  test: 
    { 
         host: '10.68.1.81',
         username: 'root',
         password: 'password',
         datebase: 'test' 
     },
  dev: 
       { 
         host: '10.68.1.81',
         username: 'root',
         password: 'password',
         database: 'dev' 
       },
  rel: 
   { 
         host: '10.68.1.81',
         username: 'root',
         password: 'password',
         database: 'rel' 
   } 
}

& 用來建立錨點(server),<< 表示合并到當前數據,* 用來引用錨點。

19.4.5 應用場景

  • 1、實現簡單,解析方便,特別適合在腳本語言中使用
  • 2、配置文件,寫YAML比XML/ini/JSON快,因為不需要關注標簽、引號、括號等

19.4.6 在線驗證網址:

http://www.bejson.com/validators/yaml/

19.4.7 YAML的Python讀寫

19.4.7.1 YAML庫安裝

? ? 在Python常用的讀寫YAML庫有pyyamlruamel

  • pyyaml安裝
pip install -U pyyaml
或
pip3 install -U pyyaml
  • ruamel安裝
pip install -U ruamel.yaml
或
pip3 install -U ruamel.yaml
19.4.7.2 Python寫YAML
19.4.7.2.1 將字典寫入YAML文件

示例代碼如下所示:

import os
import yaml

def SaveDict2YAML(path,filename,**data):
    savePath=os.path.join(path,filename)
    with open(savePath,mode="w",encoding="utf8") as fo:
        yaml.dump(data,fo,Dumper=yaml.Dumper)

if __name__=="__main__":
    testDict={
        "server":
            {
                "host": "10.68.1.81",
                "username": "root",
                "password": "password"
            },
        "ower":["test","dev","rel"]
    }
    path=os.getcwd()
    filename="dict2yaml.yaml"
    SaveDict2YAML(path,filename,data=testDict)

最終保存的文件如下所示:

data:
  ower:
  - test
  - dev
  - rel
  server:
    host: 10.68.1.81
    password: password
    username: root
19.4.7.2.2 將列表寫入YAML文件

示例代碼如下所示:

import os
import yaml

def SaveList2YAML(path,filename,data):
    savePath=os.path.join(path,filename)
    with open(savePath,mode="w",encoding="utf8") as fo:
        yaml.dump(data,fo,Dumper=yaml.Dumper)

if __name__=="__main__":
    testList=[
        "test",
        "dev",
        "rel",
        {
            "server":
                {
                    "host": "10.68.1.81",
                    "username": "root",
                    "password": "password"
                }
        }
    ]
    path=os.getcwd()
    filename="list2yaml.yaml"
    SaveList2YAML(path,filename,testList)

最終保存的文件如下所示:

- test
- dev
- rel
- server:
    host: 10.68.1.81
    password: password
    username: root
19.4.7.3 Python讀YAML
import  os
import  yaml
import json

def ReadYAML(path,filename):
    path=os.path.join(path,filename)
    with open(path,mode="r",encoding="utf8") as fo:
        data=yaml.load(fo.read(),Loader=yaml.Loader)
    return data

if __name__=="__main__":
    filename="list2yaml.yaml"
    path=os.getcwd()
    data=ReadYAML(path,filename)
    print(json.dumps(data,indent=3))

最終的打印結果如下所示:

[
   "test",
   "dev",
   "rel",
   {
      "server": {
         "host": "10.68.1.81",
         "password": "password",
         "username": "root"
      }
   }
]

如果使用ruamel寫YAML文件,需要將Dumper更換一下即可,如下所示:

yaml.dump(data,fo,Dumper=ruamelyaml.RoundTripDumper)

19.5 Excel讀寫

19.5.1 安裝openpyxl模塊

? ? Python沒有自帶openpyxl,需要自行安裝,安裝方法如下所示:

pip install -U openpyxl

驗證是否安裝成功

pip list | findstr "openpyxl"

pip show openpyxl

? ?返回以下結果即說明安裝成功

openpyxl ? ? ? 3.0.0

19.5.2 讀取Excel文檔

? ? 以下示例將使用Excel表格 data.xlsx,使用Excel 2013創建,默認包含3個sheet頁,如下所示:

190402DefaultExcelSheet.jpg
19.5.2.1 使用openpyxl打開Excel文檔

? ? 詳細代碼如下所示:

import openpyxl
import os

def getBaseDir(fileName):
    return os.path.join(os.path.dirname(__file__),fileName)

def loadWorkbook():
    workbook=openpyxl.load_workbook(getBaseDir("data.xlsx"))
    print(type(workbook))

loadWorkbook()

openpyxl.load_workbook()接受文件名,返回一個workbook數據類型的值,這個workbook對象代表這個Excel文件。需要注意的是所打開的默認必須位于當前工作目錄,否則需要傳入完整路徑,可使用 os.getcwd()
輸出結果:

<class 'openpyxl.workbook.workbook.Workbook'>
19.5.2.2 從Workbook中獲取Sheet
import openpyxl
import os

def getBaseDir(fileName):
    return os.path.join(os.path.dirname(__file__),fileName)

def loadWorkbook():
    workbook=openpyxl.load_workbook(getBaseDir("data.xlsx"))
    return  workbook

def getSheet():
    wb=loadWorkbook()
    # 獲取所有sheet表名
    print(wb.sheetnames,type(wb.sheetnames))
    # 根據sheet名字獲取sheet
    print(wb['Sheet2'],type(wb['Sheet2']))
    # 獲取激活的sheet
    print(wb.active,type(wb.active))

if __name__ == '__main__':
    getSheet()

輸出結果:

['Sheet1', 'Sheet2', 'Sheet3'] <class 'list'>
<Worksheet "Sheet2"> <class 'openpyxl.worksheet.worksheet.Worksheet'>
<Worksheet "Sheet3"> <class 'openpyxl.worksheet.worksheet.Worksheet'>
19.5.2.3 從sheet頁中獲取單元格
import openpyxl
import os

def getBaseDir(fileName):
    return os.path.join(os.path.dirname(__file__),fileName)

def loadWorkbook():
    workbook=openpyxl.load_workbook(getBaseDir("data.xlsx"))
    return  workbook

def getSheet():
    wb=loadWorkbook()
    # 獲取所有sheet表名
    print(wb.sheetnames,type(wb.sheetnames))
    # 根據sheet名字獲取sheet
    print(wb['Sheet2'],type(wb['Sheet2']))
    # 獲取激活的sheet
    print(wb.active,type(wb.active))


def getCellValue():
    wb = loadWorkbook()
    sheet=wb['Sheet2']
    cell=sheet['A1']
    # 獲取單元格的Value值
    print("Row {} Column {} Value {} ".format(cell.row,cell.column,cell.value))
    for i in range(1,10):
        for j in range(1,3):
            print(i,sheet.cell(row=i,column=j).value)


if __name__ == '__main__':
    # getSheet()
    getCellValue()

輸出結果:

Row 1 Column 1 Value A1-A1
1 A1-A1
1 B1-B1
2 A1-A2
2 B1-B2
3 A1-A3
3 B1-B3
4 A1-A4
4 B1-B4
5 A1-A5
5 B1-B5
6 A1-A6
6 B1-B6
7 A1-A7
7 B1-B7
8 A1-A8
8 B1-B8
9 A1-A9
9 B1-B9
19.5.2.4 從表中取得行和列
import openpyxl
import os

def getBaseDir(fileName):
    return os.path.join(os.path.dirname(__file__),fileName)

def loadWorkbook():
    workbook=openpyxl.load_workbook(getBaseDir("data.xlsx"))
    return  workbook

def getRowAndColumn():
    wb = loadWorkbook()
    sheet = wb['Sheet2']
    print(tuple(sheet['A1':'B8']))
    # 循環每一行
    for r in sheet['A1':'B8']:
    # 循環每一列
        for c in r:
            print("Locate is {},value is {}".format(c.coordinate,c.value))

if __name__ == '__main__':
    # getSheet()
    getRowAndColumn()

運行結果如下:

((<Cell 'Sheet2'.A1>, <Cell 'Sheet2'.B1>), (<Cell 'Sheet2'.A2>, <Cell 'Sheet2'.B2>), (<Cell 'Sheet2'.A3>, <Cell 'Sheet2'.B3>), (<Cell 'Sheet2'.A4>, <Cell 'Sheet2'.B4>), (<Cell 'Sheet2'.A5>, <Cell 'Sheet2'.B5>), (<Cell 'Sheet2'.A6>, <Cell 'Sheet2'.B6>), (<Cell 'Sheet2'.A7>, <Cell 'Sheet2'.B7>), (<Cell 'Sheet2'.A8>, <Cell 'Sheet2'.B8>))
Locate is A1,value is A1-A1
Locate is B1,value is B1-B1
Locate is A2,value is A1-A2
Locate is B2,value is B1-B2
Locate is A3,value is A1-A3
Locate is B3,value is B1-B3
Locate is A4,value is A1-A4
Locate is B4,value is B1-B4
Locate is A5,value is A1-A5
Locate is B5,value is B1-B5
Locate is A6,value is A1-A6
Locate is B6,value is B1-B6
Locate is A7,value is A1-A7
Locate is B7,value is B1-B7
Locate is A8,value is A1-A8
Locate is B8,value is B1-B8

19.5.3 寫入Excel文檔

19.5.3.1 創建和保存Excel文檔
import openpyxl
import os

def CreateNewWorkbook(path,fileName="test.xlsx"):
    workbook=openpyxl.Workbook()
    activeSheet=workbook.active
    # 給sheet取名字
    activeSheet.title="This is test sheet by openpyxl"
    print(f"current acvtive sheet is {activeSheet},name is: {activeSheet.title}\nwork book is {workbook['This is test sheet by openpyxl']} ")
    # 保存工作簿
    workbook.save(path+"\\"+fileName)

if __name__ == "__main__":
    path=r"C:\Users\Surpass\PycharmProjects\PythonIOTest\ExcelLesson"
    CreateNewWorkbook(path,fileName="SaveAsByOpenpyxl.xlsx")

運行結果如下所示:

current acvtive sheet is <Worksheet "This is test sheet by openpyxl">,name is: This is test sheet by openpyxl
work book is <Worksheet "This is test sheet by openpyxl">
190403CreateAndSave.jpg
19.5.3.2 創建和刪除sheet
import openpyxl
import os

def CreateNewAndDelete(path,fileName="test.xlsx"):
    workbook=openpyxl.Workbook()
    print(f"init sheetname is:{workbook.sheetnames}")
    # 創建Sheet
    for i in range(5):
        workbook.create_sheet(title="Sheet"+str(i),index=i)
    print(f"create sheetname is {workbook.sheetnames}")
    # 刪除Sheet
    for j in range(3):
        del workbook['Sheet'+str(j)]
    print(f"after delete sheetname is:{workbook.sheetnames}")
    # 保存Excel工作簿
    workbook.save(path+"\\"+fileName)

if __name__ == '__main__':
    path=r"C:\Users\Surpass\PycharmProjects\PythonIOTest\ExcelLesson"
    CreateNewAndDelete(path,fileName="createOrDelSheet.xlsx")

運行結果如下所示:

init sheetname is:['Sheet']
create sheetname is ['Sheet0', 'Sheet1', 'Sheet2', 'Sheet3', 'Sheet4', 'Sheet']
after delete sheetname is:['Sheet3', 'Sheet4', 'Sheet']
19.5.3.3 將值寫入單元格
import openpyxl
import os

def CreateNewAndDelete(path,fileName="test.xlsx"):
    workbook=openpyxl.Workbook()
    for i in range(5):
        workbook.create_sheet(title="Sheet"+str(i),index=i)
    # 保存Excel工作簿
    workbook.save(path+"\\"+fileName)

def InsertValutToExcel(path,fileName,sheetName,insertValue,cellRange):
    filePath=path+"\\"+fileName
    workbook=openpyxl.load_workbook(filePath)
    sheetName=workbook[sheetName]
    sheetName[cellRange]=insertValue
    print(sheetName[cellRange].value)
    workbook.save(filePath)

if __name__ == '__main__':
    path=r"C:\Users\Surpass\PycharmProjects\PythonIOTest\ExcelLesson"
    CreateNewAndDelete(path,fileName="createOrDelSheet.xlsx")
    InsertValutToExcel(path=path,fileName="createOrDelSheet.xlsx",sheetName="Sheet3",insertValue="This is test value by openpyxl",cellRange="A3")

運行結果如下所示:

19.5.4 修飾Excel文檔

? ? 對某些單元格設置字體、樣式等,可以起到強調單元格的重要性等。因此需要從openpyxl.styles中導入Font()和Style()函數。

19.5.4.1 設置字體和樣式

? ? 設置單元格字體樣式主要使用Font對象,向其傳入關鍵字參數即可,主要關鍵字參數如下所示:

關鍵字參數 數據類型 描述
name string 字體名稱,如Arial/Times New Roman
size int 字體大小
italic bool 是否采用斜體,True代表使用斜體
bold bool 是否采用粗體,True代表使用粗體
underline string 是否帶下劃線
vertAlign string 垂直對齊方式

underline:為固定的參數可選項,如下所示:

  • double:雙下劃線
  • single:單下劃線
  • doubleAccounting:會計雙下劃線
  • singleAccounting:會計單下劃線
    vertAlign:為固定的參數可選項,如下所示:
  • baseline:比較基準
  • superscript:上標
  • subscript:下標

示例代碼如下所示:

import os
from openpyxl import Workbook
from openpyxl.styles import colors
from openpyxl.styles import Font,Color

def SetExcelFont(path,fileName):
    wb=Workbook()
    sheet=wb.active
    firstFontObj=Font(name="Arial",size="18",italic=True,bold=True,underline="single",color=colors.RED)
    secondFontObj=Font(name="Times New Roman",size="24",bold=True,underline="double",vertAlign="baseline",color=colors.BLUE)
    thirdFontObj=Font(name="Calibri",size="24",italic=False,bold=True,underline="doubleAccounting",vertAlign="superscript",color="0099CC00")
    fourthFontObj=Font(name="Arial",size="34",italic=False,bold=False,underline="singleAccounting",vertAlign="subscript",color=colors.BLACK)
    sheet["A1"].font=firstFontObj
    sheet["B1"].font=secondFontObj
    sheet["A2"].font=thirdFontObj
    sheet["B2"].font=fourthFontObj
    sheet["A1"]="hello"
    sheet["B1"]="world"
    sheet["A2"]="Software"
    sheet["B2"]="Test"
    wb.save(path+"\\"+fileName)

if __name__=="__main__":
    path=r"C:\Users\Surpass\PycharmProjects\PythonIOTest\ExcelLesson"
    SetExcelFont(path,fileName="SetExcelFont.xlsx")

運行結果如下所示:

190404設置字體.jpg
19.5.4.2 添加公式

? ? 在Excel文件中,公式通常以=開始,通過其他單元格的計算得到值,使用openpyxl添加公式特別簡單,就像直接在Excel文件中添加公式一樣,現在有一份成績單,大于等于90,則評價為優,小于60為不合格,介于60和90為良好,示例代碼如下所示:

from openpyxl import load_workbook
from openpyxl import Workbook
from openpyxl.styles import Font,colors,PatternFill,fills

def AddFormula(path,fileName,sheetName="Sheet1"):
    filePath=path+"\\"+fileName
    wb=load_workbook(filePath)
    ws=wb[sheetName]
    for i in range(2,len(ws["B"])+1):
        scorePost="B"+str(i)
        formulaPos="C"+str(i)
        formulaText=f'=IF(B{i}>=90,"優",IF(B{i}<60,"不合格","良好"))'
        ws[formulaPos]=formulaText
        if int(ws[scorePost].value) >=90:
            # 寫入公式 
            ws[formulaPos].font=Font(name="Arial",color=colors.BLACK)
            # 進行單元格填充
            ws[formulaPos].fill=PatternFill(fill_type=fills.FILL_SOLID,fgColor=colors.GREEN)
        elif int(ws[scorePost].value) <60:
            ws[formulaPos].font=Font(name="Arial",color=colors.BLACK)
            ws[formulaPos].fill=PatternFill(fill_type=fills.FILL_SOLID,fgColor=colors.RED)
        else:
            ws[formulaPos].font=Font(name="Arial",color=colors.BLACK)
            ws[formulaPos].fill=PatternFill(fill_type=fills.FILL_SOLID,fgColor=colors.BLUE)
    wb.save(filePath)

if __name__=="__main__":
    path=r"C:\Users\Surpass\PycharmProjects\PythonIOTest\ExcelLesson"
    AddFormula(path,fileName="AddFormula.xlsx")

運行的結果如下所示:

190404AddFormula.jpg

注意事項

  • 如果在調用load_workbook()不帶參數data_only=True,則帶公式的單元格,在獲取單元格內容為其公式,如果僅希望獲取單元格值,則需要帶上data_only=True參數
19.5.4.3 調整行高和列寬

? ? 在Excel中,調整行高和列寬非常容易,今天我們來用代碼嘗試一下調整行高和列寬。主要涉及到Worksheet對象row_dimensionscolumn_demiensions

示例代碼如下所示:

from openpyxl import Workbook

def SetHeightAndWidth(path,fileName="test.xlsx"):
    filePath=path+"\\"+fileName
    wb=Workbook()
    ws=wb.active
    ws["A1"]="Set Row Heigh"
    ws["B1"]="Set Column Widht"
    ws.row_dimensions[1].height=80
    ws.column_dimensions['B'].width=50
    wb.save(filePath)

if __name__=="__main__":
    path=r"C:\Users\Surpass\PycharmProjects\PythonIOTest\ExcelLesson"
    fileName="SetHeightAndWidth.xlsx"
    SetHeightAndWidth(path,fileName=fileName)

運行結果如下所示:

190404SetHeightAndWidth.jpg

19.6 對象序列化

? ? 在Python,如果需要將任意對象保存到磁盤中,必須要進行轉換為其相應的格式,如dict類型的數據是不能直接按文本格式保存的。在Python中,能實現任意對象與文本之間的相互轉化,同時也可以將任意對象與二進制之間相互轉化的稱為序列化,使用的模塊為pickle。

? ? 使用Python的pickle操作,可以將對象序列化字符串、文件等類似于文件的任意對象;也可以將這些字符串、文件或任意類似于文件的對象還原為原來的對象。

19.6.1 pickle模塊方法

? ? pickle模塊中,常用的方法如下所示:

  • dumps:將Python中的對象序列化二進制對象
  • loads:從指定的pickle數據讀取并返回對象
  • dump:將Python中的對象序列化二進制對象,并保存為文件
  • load:讀取指定的序列化數據文件,并返回對象

? ? 以上4個方法又可以分為兩類:

  • dumps和loads:是基于內存的Python對象與二進制相互轉化
  • dump和load:是基于文件的Python對象與二進制相互轉化

19.6.2 dumps和dump

19.6.2.1 dumps

? ? dumps其主要功能:將Python對象轉換為二進制,方法的詳細定義如下所示:

dumps(obj, protocol=None, *, fix_imports=True)
  • obj:要轉換的Python對象
  • protocol:pickle的轉碼協議,取值0、1、2、3、4,默認為3。
    • 0:ASCII碼
    • 2:舊版本的二進制協議
    • 3:新版本的二進制協議
    • 4:更新版本的二進制協議
19.6.2.2 dump

? ? dumps其主要功能:將Python對象轉換為二進制文件,方法的詳細定義如下所示:

dump(obj, file, protocol=None, *, fix_imports=True)
  • obj:要轉換的Python對象
  • file:序列化后要保存的文件
  • protocol:pickle的轉碼協議,取值0、1、2、3、4,默認為3。
    • 0:ASCII碼
    • 2:舊版本的二進制協議
    • 3:新版本的二進制協議
    • 4:更新版本的二進制協議

序列化的文件擴展名為pkl

19.6.3 loads和load

19.6.3.1 loads

? ? loads其主要功能:將二進制對象轉換為Python對象,方法的詳細定義如下所示:

loads(s, *, fix_imports=True, encoding="ASCII", errors="strict")
  • s:要轉換的二進制對象

? ? 在將二進制對象反序列化為Python對象時,會自動識別轉碼協議,一般不需要傳入轉碼協議參數值。當待轉換的二進制對象的字節數據超過pickle的Python對象時,多余的字節將被忽略

19.6.3.2 load

? ? load其主要功能:將二進制對象文件轉換為Python對象,方法的詳細定義如下所示:

load(file, *, fix_imports=True, encoding="ASCII", errors="strict")
  • file:二進制對象文件

19.6.4 pickle示例

1.dumps和loads

>>> import pickle
>>> tempDict={"a":1,"b":2,"c":3}
>>> pA=pickle.dumps(tempDict)
>>> pA
b'\x80\x03}q\x00(X\x01\x00\x00\x00aq\x01K\x01X\x01\x00\x00\x00bq\x02K\x02X\x01\x00\x00\x00cq\x03K\x03u.'
>>> pB=pickle.loads(pA)
>>> pB
{'a': 1, 'b': 2, 'c': 3}

2.dump和load

import os
import pickle

def saveAsPickleObj(path:str,data:str,filename="Serialization.pkl"):
    savePath=os.path.join(path,filename)
    try:
        with open(savePath,"wb",pickle.HIGHEST_PROTOCOL) as fo:
            pickle.dump(data,fo)
    except Exception as ex:
        print(f"save error\n{ex}")

def readPickleObj(path:str,filename):
    filePath=os.path.join(path,filename)
    flag= True if all((os.path.exists(filePath),os.path.isfile(filePath))) else False
    if flag:
        try:
           with open(filePath,mode="rb") as fo:
               result=pickle.load(fo)
        except Exception as ex:
            print(f"read error\n{ex}")
        else:
            return result

if __name__ == '__main__':
    tempDict={"a":1,"b":2,"c":3}
    path=os.getcwd()
    filename="sample.pkl"
    saveAsPickleObj(path,tempDict,filename)
    result=readPickleObj(path,filename)
    print(result)

? ? 代碼運行完成之后,會目錄生成一個sample.pkl文件。

本文地址:http://www.lxweimin.com/p/8ceb3f881e58

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 228,345評論 6 531
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 98,494評論 3 416
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 176,283評論 0 374
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 62,953評論 1 309
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 71,714評論 6 410
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 55,186評論 1 324
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,255評論 3 441
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,410評論 0 288
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 48,940評論 1 335
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 40,776評論 3 354
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 42,976評論 1 369
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,518評論 5 359
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,210評論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,642評論 0 26
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,878評論 1 286
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 51,654評論 3 391
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 47,958評論 2 373