Python基礎(chǔ)-19文件讀寫

19. 文件讀寫

19.1 文件操作

? ? 數(shù)據(jù)持久化答恶,是將程序中的對(duì)象以數(shù)據(jù)的方式保存到磁盤上,在程序下次運(yùn)行時(shí),可以將數(shù)據(jù)從磁盤上恢復(fù)到內(nèi)存中即纲。數(shù)據(jù)持久化的方式有很多,而最為常見(jiàn)的方式是將數(shù)據(jù)以文件的形式保存博肋。在Python中低斋,可以通過(guò)內(nèi)置函數(shù)的方法進(jìn)行文件的讀、寫匪凡、刪除等操作膊畴。

19.1.1 文件的基本操作

? ? 文件的基本操作比較多,如創(chuàng)建病游、刪除唇跨、修改權(quán)限、寫入衬衬、讀取等等买猖。

  • 刪除、修改權(quán)限:作用于文件本身佣耐,屬于系統(tǒng)級(jí)操作
  • 讀取、寫入:是文件最常用的操作唧龄,作用于文件內(nèi)容兼砖,屬于應(yīng)用級(jí)操作

? ? 文件的系統(tǒng)級(jí)操作奸远,一般使用Python中的os、sys等模塊讽挟。

19.1.2 讀寫文件的一般步驟

? ? 讀寫文件一般常分為3步懒叛,每一步可使用相應(yīng)的方法

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

一個(gè)文件耽梅,必須在打開之后才可以對(duì)其進(jìn)行相應(yīng)的操作,并在操作完成均完成進(jìn)行關(guān)閉。

19.1.2.1 打開文件

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

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

? ? 比較關(guān)鍵的參數(shù)如下所示:

  • file:打開的文件名窃祝,屬于字符串類型,但如果文件名含有特殊字符众旗,需要進(jìn)行轉(zhuǎn)義罢杉。
  • mode:打開文件的方式,如只讀贡歧、只寫滩租、讀寫、二進(jìn)制等等產(chǎn)利朵,默認(rèn)為只讀律想。
  • encoding:如直接保存為文件文本,需要指定編碼格式绍弟,不然會(huì)造成讀取文件文件出現(xiàn)亂碼

? ? mode的詳細(xì)介紹如下所示:

mode 含義
r 只讀技即,但文件必須存在
w 只寫,如果文件已經(jīng)存在晌柬,則覆蓋姥份,不存在,則重新創(chuàng)建
a 以只寫的文件打開文件年碘,并在文件后追加內(nèi)容澈歉,如果文件不存在,則創(chuàng)建新文件
b 以二進(jìn)制形式打開屿衅,不能單獨(dú)使用
+ 以讀寫形式打開文件埃难, 不能單獨(dú)使用
r+ 以讀寫形式打開文件,文件必須存在涤久,當(dāng)寫入時(shí)涡尘,會(huì)清空原內(nèi)容
w+ 以讀寫形式打開文件,文件不存在則創(chuàng)建文件响迂,如已經(jīng)存在考抄,當(dāng)寫入時(shí),會(huì)清空原內(nèi)容
a+ 以讀寫形式打開文件蔗彤,文件不存在則創(chuàng)建文件川梅,如已經(jīng)存在疯兼,當(dāng)寫入時(shí),在文件后追加原內(nèi)容

以上僅為常見(jiàn)的一些模式贫途,實(shí)際應(yīng)用還可使用組合模式吧彪,即同時(shí)使用多種模式來(lái)操作文件,如rb丢早、wb姨裸、wb+、ab等

? ? 另外根據(jù)操作系統(tǒng)的不同怨酝,又可以分為文本模式二進(jìn)制模式傀缩,其主要區(qū)別如下所示:

  • 在Windows系統(tǒng)中,文本模式下Windows平臺(tái)的末尾換行符為\r\n凫碌,在讀取時(shí)轉(zhuǎn)換為\n扑毡,而在寫入時(shí)又將\n轉(zhuǎn)換為\r\n。這種隱藏的行為對(duì)于文本文件是沒(méi)有問(wèn)題的盛险,但如果以文本模式打開二進(jìn)制數(shù)據(jù)文件(如圖片瞄摊、EXE程序等)則會(huì)發(fā)生問(wèn)題,因改變了文件的具體內(nèi)容苦掘。
  • 在Unix/Linux系統(tǒng)中换帜,末尾換行符為\n,因此兩者沒(méi)有區(qū)別
19.1.2.2 具體讀寫操作

? ? 通過(guò)open方法得到文件對(duì)象后鹤啡,就可以對(duì)文件進(jìn)行操作惯驼,常用的方式是讀和寫。

1.讀取文件

? ? 通過(guò)調(diào)用文件對(duì)象的read方法可以獲得文件的內(nèi)容递瑰,示例代碼如下所示:

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

? ? 打開文件后祟牲,文件對(duì)象fo中的read方法,會(huì)將文件的全部?jī)?nèi)容一次性讀取到內(nèi)存中抖部。

2.寫入文件

? ? 將字符串寫入文件说贝,可以調(diào)用文件對(duì)象的write方法,示例代碼如下所示:

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

如果文件是以二進(jìn)制形式打開慎颗,則只能以二進(jìn)制形式寫入數(shù)據(jù)乡恕。

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

? ? 直接使用文件對(duì)象的close方法即可。在打開文件并全部操作完之后俯萎,需要及時(shí)關(guān)閉傲宜。否則會(huì)導(dǎo)致其他操作出錯(cuò),如刪除夫啊、移動(dòng)等函卒,則提示文件正在使用。

19.1.3 文件對(duì)象方法

? ? 常見(jiàn)的文件對(duì)象方法如下所示:

方法 描述
read(size) 讀取指定size的字節(jié)數(shù)據(jù)撇眯,然后作為字符串或bytes對(duì)象返回报嵌,size為可選參數(shù)躁愿,如未指定,則默認(rèn)文件所有內(nèi)容
readline() 讀取一行沪蓬,并在字符串末尾留下?lián)Q行符\n,如果到文件尾来候,則返回空字符串
readlines() 讀取所有行跷叉,并保存至列表中,每個(gè)元素代表一行营搅,類似于list(fo)
writer(string) 將string寫入到文件中云挟,返回寫入的字符數(shù),如果以二進(jìn)制模式转质,則需要將string轉(zhuǎn)換為bytes對(duì)象
tell() 返回文件對(duì)象當(dāng)前所在位置园欣,從文件開頭開始計(jì)算字節(jié)數(shù)
seek(offset,from_what) 改變文件對(duì)象所處的位置。offset是相對(duì)參考位置的偏移量休蟹,from_what表示參考位置沸枯,0-文件頭,默認(rèn)赂弓;1-當(dāng)前位置绑榴;2-文件尾

19.1.4 文件對(duì)象迭代器

? ? 文件對(duì)象本身也是一個(gè)迭代器,可以與for循環(huán)配合進(jìn)行文件的讀取盈魁。示例如下所示:

>>> 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循環(huán)中翔怎,每循環(huán)一次,相當(dāng)于調(diào)用了一次readline方法杨耙。

19.1.5 使用with簡(jiǎn)化文件操作

? ? 通過(guò)以上你會(huì)發(fā)現(xiàn)赤套,每次使用文件操作,都需要3個(gè)步驟珊膜。那有沒(méi)有簡(jiǎn)便的辦法來(lái)簡(jiǎn)化這些操作了容握?Python內(nèi)置了with語(yǔ)句,使用其可以簡(jiǎn)化這種寫法辅搬,在調(diào)用完成之后唯沮,with語(yǔ)句會(huì)自動(dòng)關(guān)閉。其語(yǔ)法格式如下所示:

with 表達(dá)式 as 變量:
    doSomething

針對(duì)文件操作而言堪遂,表達(dá)式就是open函數(shù)介蛉,as后面的變量就是open返回的文件對(duì)象。

? ? 示例代碼如下所示:

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 字符串與二進(jìn)制的轉(zhuǎn)化

? ? 在處理文件操作時(shí)溶褪,常用的做法是以二進(jìn)制形式保存币旧,以文件方式使用。一是二進(jìn)制文件更小猿妈,便于網(wǎng)絡(luò)傳輸和存儲(chǔ)吹菱,另外也可以避免保存與讀取編碼不同造成的亂碼情況巍虫。

19.1.6.1 將字符串轉(zhuǎn)換為二進(jìn)制數(shù)

? ? 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 將二進(jìn)制數(shù)轉(zhuǎn)換為字符串

? ? 如果將二進(jìn)制數(shù)轉(zhuǎn)換為字符串,可以調(diào)用二進(jìn)制對(duì)象的decode方法鳍刷,并傳入指定的解碼格式占遥,示例如下所示:

>>> tempB=bytes("我愛(ài)中國(guó),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

? ? 程序報(bào)錯(cuò)了输瓜,這個(gè)問(wèn)題仔細(xì)看看瓦胎,就知道原因所在了,編碼使用gb2312尤揣,解碼使用了utf8搔啊。因此在做轉(zhuǎn)換時(shí),需要避免這種情況發(fā)生北戏,

>>> tempB=bytes("我愛(ài)中國(guó)负芋,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)中國(guó),I love China

? ? Windows平臺(tái)與Linux平臺(tái)編碼解碼是有區(qū)別的嗜愈,主要如下所示:

  • 在Linux平臺(tái)中旧蛾,生成的文件默認(rèn)編碼是utf8格式,所以解碼需要指定解碼格式應(yīng)為utf8
  • 在Windows平臺(tái)中蠕嫁,中文操作系統(tǒng)生成文件默認(rèn)為gb2312/gbk格式蚜点,所以解碼需要指定為相應(yīng)的編碼格式才能正常解碼

為避免因操作系統(tǒng)不同,因此在轉(zhuǎn)換時(shí)需要顯式指定相應(yīng)的編碼和解碼格式

19.2 json讀寫

? ? 在日常種類接口測(cè)試中拌阴,會(huì)經(jīng)常處理JSON格式的請(qǐng)求報(bào)文和響應(yīng)報(bào)文等绍绘,平時(shí)用得最多的也是Python自帶的json包,其提供了4個(gè)方法dumps迟赃、dump陪拘、loadsload纤壁。

? ? 1左刽、JSON不能存儲(chǔ)每一種Python值,僅能存儲(chǔ)以下數(shù)據(jù)類型的傳下

  • 字符串
  • 整形
  • 浮點(diǎn)型
  • 布爾型
  • 列表
  • 字典
  • NoneType

? ? 2酌媒、JSON不能表示Python對(duì)象欠痴,如File對(duì)象、CSV Reader秒咨、Regex對(duì)象等

19.2.1 查看json的使用方法

import json
print(json.__all__)

輸出結(jié)果為:

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

19.2.2 json 讀取

? ? json包常用的讀取方法為loads喇辽、load

loads:可理解為load string,其功能是將json格式的字符串轉(zhuǎn)換為Python數(shù)據(jù)類型(字典)
load:讀取json文件雨席,將轉(zhuǎn)換為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實(shí)戰(zhàn)"
}"""

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)},不是字符串")

輸出結(jié)果

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

需要注意兩點(diǎn):
1菩咨、傳入的數(shù)據(jù)一定要是字符串格式,如果傳入字典則會(huì)出錯(cuò)
2、建議增加字符串編碼格式抽米,防止出現(xiàn)亂碼

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}")

輸出結(jié)果

data is
{'book': 'json in action', 'author': 'Surpassme', 'isbn': 961839721541, '中文名': 'JSON實(shí)戰(zhàn)'}

19.2.3 json保存

? ? json包常用的讀取方法為dumps特占、dump

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

19.2.3.1 dumps

dumps常用用法如下所示:

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

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

示例如下所示:

import json

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

運(yùn)行結(jié)果如下所示:

{
 "book": "json in action",
 "author": "Surpassme",
 "isbn": 961839721541,
 "中文名": "JSON實(shí)戰(zhàn)"
}
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實(shí)戰(zhàn)"
     }
     path=os.getcwd()+"\\jsonfile.json"
     SavaAsJsonFile(path,jsonStr,indent=1)

運(yùn)行結(jié)果如下所示:

{
 "book": "json in action",
 "author": "Surpassme",
 "isbn": 961839721541,
 "中文名": "JSON實(shí)戰(zhàn)"
}

19.3 csv讀寫

? ? csv(Comma-Separated Values)一般是特指以逗號(hào)做為分隔符的文本文件标捺。因使用簡(jiǎn)單方便胖笛,平時(shí)在測(cè)試過(guò)程也會(huì)經(jīng)常用到該類型文件。今天就來(lái)學(xué)習(xí)一下在Python中如何處理csv文件宜岛。

19.3.1 CSV讀取

19.3.1.1 常規(guī)讀取

讀取CSV文件常用的步驟為,創(chuàng)建一個(gè)CSV文件對(duì)象功舀,打開文件進(jìn)行讀取

  • 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)
  • 運(yùn)行結(jié)果如下所示:
['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文件第一行為標(biāo)題行萍倡,余下全部為數(shù)據(jù),則可以采用字典形式進(jìn)行讀取辟汰。 以此種方式讀取時(shí)列敲,會(huì)默認(rèn)將第一行(標(biāo)題)做為Key值,從第二行開始做為數(shù)據(jù)內(nèi)容即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)
  • 運(yùn)行結(jié)果如下所示:
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 常規(guī)寫入

讀取CSV文件常用的步驟為帖汞,創(chuàng)建一個(gè)CSV文件對(duì)象戴而,打開文件進(jìn)行寫入

  • 示例代碼如下所示:
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文件出現(xiàn)空白行翩蘸,則在with open(...,newline="")增加參數(shù)newline=""
2所意、CSV.Writer中的方法writerow()方法接受一個(gè)列表參數(shù)。列表中的每個(gè)詞催首,放在輸出的CSV文件中的一個(gè)單元格中扶踊。writerow()函數(shù)的返回值,是寫入文件中這一行的字符數(shù)(包含換行符)

  • 運(yùn)行結(jié)果如下所示:
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 字典形式寫入

? ? 如果我們要?jiǎng)?chuàng)建帶有標(biāo)題和數(shù)據(jù)的CSV文件郎任,則可以采用以字典形式進(jìn)行保存文件秧耗。

  • 示例代碼如下所示:
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基礎(chǔ)教程","Author":"Surpassme","ISBN":1088021365},
        {"ID":"2","Name":"Java基礎(chǔ)教程","Author":"Surpassme","ISBN":2088021365},
        {"ID":"3","Name":"C#基礎(chǔ)教程","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)

以字典形式保存時(shí),需要注意標(biāo)題即為字典的Key值

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

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

  • 示例代碼如下所示:
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")
  • 運(yùn)行結(jié)果如下所示:
190202自定義分隔符和終止符.jpg

19.3.3 示例項(xiàng)目

? ? 假設(shè)現(xiàn)在有一個(gè)任務(wù)霉猛,從一個(gè)文件夾中刪除所有CSV文件的第一行尺锚。主要方法如下所示:

  • 依次逐個(gè)打開CSV文件,刪除第一行數(shù)據(jù)惜浅,再保存
  • 在網(wǎng)上找找有沒(méi)有相應(yīng)的工具
  • 自己使用代碼編寫工具

? ? 今天我們就來(lái)嘗試用Python來(lái)解決該任務(wù)缩麸。先來(lái)分析一下,使用代碼需要解決的問(wèn)題點(diǎn)有哪些

  • 過(guò)濾到文件為CSV類型的文件
  • 讀取每個(gè)文件的全部?jī)?nèi)容
  • 刪除CSV文件的第一行,并保存為CSV文件

在使用工具或代碼來(lái)修改文件時(shí)杭朱,需要將數(shù)據(jù)或文件進(jìn)行備份

詳細(xì)示例如下所示:

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):
    """創(chuàng)建另存文件夾"""
    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)

最終的運(yùn)行效果如下所示:

190203項(xiàng)目示意圖.jpg

19.4 YAML讀寫

19.4.1 YAML簡(jiǎn)介

? ? YAML是YAML Ain't Markup Language的遞歸縮寫阅仔,意思其實(shí)是:"Yet Another Markup Language"。YAML 的語(yǔ)法和其他高級(jí)語(yǔ)言類似弧械,并且可以簡(jiǎn)單表達(dá)清單八酒、散列表,標(biāo)量等數(shù)據(jù)形態(tài)刃唐。它使用空白符號(hào)縮進(jìn)和大量依賴外觀的特色羞迷,特別適合用來(lái)表達(dá)或編輯數(shù)據(jù)結(jié)構(gòu)、各種配置文件画饥、傾印調(diào)試內(nèi)容衔瓮、文件大綱,其擴(kuò)展名為.yml.

19.4.2 基本語(yǔ)法

  • 區(qū)分大小寫
  • 使用縮進(jìn)表示層級(jí)關(guān)系抖甘,同層元素左對(duì)齊
  • 縮進(jìn)時(shí)不允許使用Tab鍵热鞍,只允許使用空格。
  • 縮進(jìn)的空格數(shù)目不重要衔彻,只要相同層級(jí)的元素左側(cè)對(duì)齊即可
  • 字串一般不使用引號(hào)薇宠,但必要的時(shí)候可以用引號(hào)框住
  • 使用雙引號(hào)表示字串時(shí),可用**進(jìn)行特殊字符轉(zhuǎn)義
  • #表示注釋

19.4.3 數(shù)據(jù)類型

  • 對(duì)象:鍵值對(duì)的集合艰额,又稱為映射(mapping)/ 哈希(hashes) / 字典(dictionary)
  • 數(shù)組:一組按次序排列的值澄港,又稱為序列(sequence) / 列表(list)
  • 純量(scalars):?jiǎn)蝹€(gè)的、不可再分的值
19.4.3.1 對(duì)象
  • 對(duì)象通常是鍵值對(duì)形式(key: value)柄沮,冒號(hào)后面要加一個(gè)空格回梧。示例如下所示:
key: 
    ckey1: cvalue1
    ckey2:  cvalue2
    ckey3:
          cckey1:  ccvalue1
          cckye2:  ccvalue2
    ckey4:  cvalue4

key: {ckey1: cvalue1, ckey2:  cvalue2,ckey3: {cckey1:  ccvalue1, cckye2:  ccvalue2},  ckey4:  cvalue4}
  • 使用?+空格表示復(fù)雜鍵,當(dāng)鍵是一個(gè)列表或鍵值表時(shí)祖搓,就需要使用該符號(hào)進(jìn)行表示漂辐。示例如下所示:
?
   - Red
   - Green
   - Blue
:
   - Color

以上等價(jià)于

 {[blue, reg, green]: Color}
19.4.3.2 數(shù)組

- 開頭的行表示構(gòu)成一個(gè)數(shù)組

  • 一維數(shù)組
- Red
- Green
- Blue

以上等價(jià)于

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

以上等價(jià)于

[ [ 'Red', 'Green', 'Blue' ], [ 'apple', 'tree', 'ocean' ] ]
  • 復(fù)雜結(jié)構(gòu)

對(duì)象和數(shù)組可以組合成更為復(fù)雜的結(jié)構(gòu),示例如下所示:

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

以上等價(jià)于:

{
 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 純量

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

  • 字符串
  • 布爾值
  • 整數(shù)
  • 浮點(diǎn)數(shù)
  • Null
  • 時(shí)間
  • 日期

示例如下所示:

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

顯示結(jié)果如下所示:

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都可以

顯示結(jié)果如下所示:

isMatch: [ true, false ]
  • 整數(shù)與浮點(diǎn)數(shù)
intNum:
  - 123
  - 0b11100011
  - 0x12A
floatNum:
  - 123.25
  - 3.1415392e+5

顯示結(jié)果如下所示:

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

顯示結(jié)果如下所示:

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

顯示結(jié)果如下所示:

datetime: Sun Jan 19 2020 10:34:30 GMT+0800 (中國(guó)標(biāo)準(zhǔn)時(shí)間),
date: Sun Jan 19 2020 08:00:00 GMT+0800 (中國(guó)標(biāo)準(zhǔn)時(shí)間),
time: 38070,

19.4.4 引用

錨點(diǎn)&和別名*,可以用來(lái)引用护姆,示例如下所示:

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

最終顯示的結(jié)果如下所示:

{ 
   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' 
   } 
}

& 用來(lái)建立錨點(diǎn)(server)矾端,<< 表示合并到當(dāng)前數(shù)據(jù),* 用來(lái)引用錨點(diǎn)卵皂。

19.4.5 應(yīng)用場(chǎng)景

  • 1秩铆、實(shí)現(xiàn)簡(jiǎn)單,解析方便灯变,特別適合在腳本語(yǔ)言中使用
  • 2殴玛、配置文件,寫YAML比XML/ini/JSON快添祸,因?yàn)椴恍枰P(guān)注標(biāo)簽滚粟、引號(hào)、括號(hào)等

19.4.6 在線驗(yàn)證網(wǎng)址:

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

19.4.7 YAML的Python讀寫

19.4.7.1 YAML庫(kù)安裝

? ? 在Python常用的讀寫YAML庫(kù)有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))

最終的打印結(jié)果如下所示:

[
   "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沒(méi)有自帶openpyxl,需要自行安裝蔬咬,安裝方法如下所示:

pip install -U openpyxl

驗(yàn)證是否安裝成功

pip list | findstr "openpyxl"

pip show openpyxl

? ?返回以下結(jié)果即說(shuō)明安裝成功

openpyxl ? ? ? 3.0.0

19.5.2 讀取Excel文檔

? ? 以下示例將使用Excel表格 data.xlsx,使用Excel 2013創(chuàng)建沐寺,默認(rèn)包含3個(gè)sheet頁(yè)林艘,如下所示:

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

? ? 詳細(xì)代碼如下所示:

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()接受文件名,返回一個(gè)workbook數(shù)據(jù)類型的值混坞,這個(gè)workbook對(duì)象代表這個(gè)Excel文件狐援。需要注意的是所打開的默認(rèn)必須位于當(dāng)前工作目錄,否則需要傳入完整路徑究孕,可使用 os.getcwd()
輸出結(jié)果:

<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))
    # 根據(jù)sheet名字獲取sheet
    print(wb['Sheet2'],type(wb['Sheet2']))
    # 獲取激活的sheet
    print(wb.active,type(wb.active))

if __name__ == '__main__':
    getSheet()

輸出結(jié)果:

['Sheet1', 'Sheet2', 'Sheet3'] <class 'list'>
<Worksheet "Sheet2"> <class 'openpyxl.worksheet.worksheet.Worksheet'>
<Worksheet "Sheet3"> <class 'openpyxl.worksheet.worksheet.Worksheet'>
19.5.2.3 從sheet頁(yè)中獲取單元格
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))
    # 根據(jù)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()

輸出結(jié)果:

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']))
    # 循環(huán)每一行
    for r in sheet['A1':'B8']:
    # 循環(huán)每一列
        for c in r:
            print("Locate is {},value is {}".format(c.coordinate,c.value))

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

運(yùn)行結(jié)果如下:

((<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 創(chuàng)建和保存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")

運(yùn)行結(jié)果如下所示:

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 創(chuàng)建和刪除sheet
import openpyxl
import os

def CreateNewAndDelete(path,fileName="test.xlsx"):
    workbook=openpyxl.Workbook()
    print(f"init sheetname is:{workbook.sheetnames}")
    # 創(chuàng)建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")

運(yùn)行結(jié)果如下所示:

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")

運(yùn)行結(jié)果如下所示:

19.5.4 修飾Excel文檔

? ? 對(duì)某些單元格設(shè)置字體啥酱、樣式等,可以起到強(qiáng)調(diào)單元格的重要性等厨诸。因此需要從openpyxl.styles中導(dǎo)入Font()和Style()函數(shù)镶殷。

19.5.4.1 設(shè)置字體和樣式

? ? 設(shè)置單元格字體樣式主要使用Font對(duì)象,向其傳入關(guān)鍵字參數(shù)即可微酬,主要關(guān)鍵字參數(shù)如下所示:

關(guān)鍵字參數(shù) 數(shù)據(jù)類型 描述
name string 字體名稱绘趋,如Arial/Times New Roman
size int 字體大小
italic bool 是否采用斜體,True代表使用斜體
bold bool 是否采用粗體颗管,True代表使用粗體
underline string 是否帶下劃線
vertAlign string 垂直對(duì)齊方式

underline:為固定的參數(shù)可選項(xiàng)陷遮,如下所示:

  • double:雙下劃線
  • single:?jiǎn)蜗聞澗€
  • doubleAccounting:會(huì)計(jì)雙下劃線
  • singleAccounting:會(huì)計(jì)單下劃線
    vertAlign:為固定的參數(shù)可選項(xiàng),如下所示:
  • baseline:比較基準(zhǔn)
  • superscript:上標(biāo)
  • subscript:下標(biāo)

示例代碼如下所示:

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")

運(yùn)行結(jié)果如下所示:

190404設(shè)置字體.jpg
19.5.4.2 添加公式

? ? 在Excel文件中垦江,公式通常以=開始帽馋,通過(guò)其他單元格的計(jì)算得到值,使用openpyxl添加公式特別簡(jiǎn)單,就像直接在Excel文件中添加公式一樣绽族,現(xiàn)在有一份成績(jī)單姨涡,大于等于90,則評(píng)價(jià)為優(yōu)项秉,小于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,"優(yōu)",IF(B{i}<60,"不合格","良好"))'
        ws[formulaPos]=formulaText
        if int(ws[scorePost].value) >=90:
            # 寫入公式 
            ws[formulaPos].font=Font(name="Arial",color=colors.BLACK)
            # 進(jìn)行單元格填充
            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")

運(yùn)行的結(jié)果如下所示:

190404AddFormula.jpg

注意事項(xiàng)

  • 如果在調(diào)用load_workbook()不帶參數(shù)data_only=True娄蔼,則帶公式的單元格怖喻,在獲取單元格內(nèi)容為其公式,如果僅希望獲取單元格值岁诉,則需要帶上data_only=True參數(shù)
19.5.4.3 調(diào)整行高和列寬

? ? 在Excel中锚沸,調(diào)整行高和列寬非常容易,今天我們來(lái)用代碼嘗試一下調(diào)整行高和列寬涕癣。主要涉及到Worksheet對(duì)象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)

運(yùn)行結(jié)果如下所示:

190404SetHeightAndWidth.jpg

19.6 對(duì)象序列化

? ? 在Python,如果需要將任意對(duì)象保存到磁盤中坠韩,必須要進(jìn)行轉(zhuǎn)換為其相應(yīng)的格式距潘,如dict類型的數(shù)據(jù)是不能直接按文本格式保存的。在Python中只搁,能實(shí)現(xiàn)任意對(duì)象與文本之間的相互轉(zhuǎn)化音比,同時(shí)也可以將任意對(duì)象與二進(jìn)制之間相互轉(zhuǎn)化的稱為序列化,使用的模塊為pickle氢惋。

? ? 使用Python的pickle操作洞翩,可以將對(duì)象序列化字符串、文件等類似于文件的任意對(duì)象焰望;也可以將這些字符串骚亿、文件或任意類似于文件的對(duì)象還原為原來(lái)的對(duì)象。

19.6.1 pickle模塊方法

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

  • dumps:將Python中的對(duì)象序列化二進(jìn)制對(duì)象
  • loads:從指定的pickle數(shù)據(jù)讀取并返回對(duì)象
  • dump:將Python中的對(duì)象序列化二進(jìn)制對(duì)象策州,并保存為文件
  • load:讀取指定的序列化數(shù)據(jù)文件凹蜂,并返回對(duì)象

? ? 以上4個(gè)方法又可以分為兩類:

  • dumps和loads:是基于內(nèi)存的Python對(duì)象與二進(jìn)制相互轉(zhuǎn)化
  • dump和load:是基于文件的Python對(duì)象與二進(jìn)制相互轉(zhuǎn)化

19.6.2 dumps和dump

19.6.2.1 dumps

? ? dumps其主要功能:將Python對(duì)象轉(zhuǎn)換為二進(jìn)制遥昧,方法的詳細(xì)定義如下所示:

dumps(obj, protocol=None, *, fix_imports=True)
  • obj:要轉(zhuǎn)換的Python對(duì)象
  • protocol:pickle的轉(zhuǎn)碼協(xié)議矢洲,取值0、1足陨、2嫂粟、3、4墨缘,默認(rèn)為3星虹。
    • 0:ASCII碼
    • 2:舊版本的二進(jìn)制協(xié)議
    • 3:新版本的二進(jìn)制協(xié)議
    • 4:更新版本的二進(jìn)制協(xié)議
19.6.2.2 dump

? ? dumps其主要功能:將Python對(duì)象轉(zhuǎn)換為二進(jìn)制文件零抬,方法的詳細(xì)定義如下所示:

dump(obj, file, protocol=None, *, fix_imports=True)
  • obj:要轉(zhuǎn)換的Python對(duì)象
  • file:序列化后要保存的文件
  • protocol:pickle的轉(zhuǎn)碼協(xié)議,取值0宽涌、1平夜、2、3卸亮、4忽妒,默認(rèn)為3。
    • 0:ASCII碼
    • 2:舊版本的二進(jìn)制協(xié)議
    • 3:新版本的二進(jìn)制協(xié)議
    • 4:更新版本的二進(jìn)制協(xié)議

序列化的文件擴(kuò)展名為pkl

19.6.3 loads和load

19.6.3.1 loads

? ? loads其主要功能:將二進(jìn)制對(duì)象轉(zhuǎn)換為Python對(duì)象兼贸,方法的詳細(xì)定義如下所示:

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

? ? 在將二進(jìn)制對(duì)象反序列化為Python對(duì)象時(shí)段直,會(huì)自動(dòng)識(shí)別轉(zhuǎn)碼協(xié)議,一般不需要傳入轉(zhuǎn)碼協(xié)議參數(shù)值溶诞。當(dāng)待轉(zhuǎn)換的二進(jìn)制對(duì)象的字節(jié)數(shù)據(jù)超過(guò)pickle的Python對(duì)象時(shí)鸯檬,多余的字節(jié)將被忽略

19.6.3.2 load

? ? load其主要功能:將二進(jìn)制對(duì)象文件轉(zhuǎn)換為Python對(duì)象螺垢,方法的詳細(xì)定義如下所示:

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

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)

? ? 代碼運(yùn)行完成之后喧务,會(huì)目錄生成一個(gè)sample.pkl文件。

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

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末枉圃,一起剝皮案震驚了整個(gè)濱河市功茴,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌孽亲,老刑警劉巖坎穿,帶你破解...
    沈念sama閱讀 217,509評(píng)論 6 504
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異墨林,居然都是意外死亡赁酝,警方通過(guò)查閱死者的電腦和手機(jī)犯祠,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,806評(píng)論 3 394
  • 文/潘曉璐 我一進(jìn)店門旭等,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人衡载,你說(shuō)我怎么就攤上這事搔耕。” “怎么了痰娱?”我有些...
    開封第一講書人閱讀 163,875評(píng)論 0 354
  • 文/不壞的土叔 我叫張陵弃榨,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我梨睁,道長(zhǎng)鲸睛,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,441評(píng)論 1 293
  • 正文 為了忘掉前任坡贺,我火速辦了婚禮官辈,結(jié)果婚禮上箱舞,老公的妹妹穿的比我還像新娘。我一直安慰自己拳亿,他們只是感情好晴股,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,488評(píng)論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著肺魁,像睡著了一般电湘。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上鹅经,一...
    開封第一講書人閱讀 51,365評(píng)論 1 302
  • 那天寂呛,我揣著相機(jī)與錄音,去河邊找鬼瞬雹。 笑死昧谊,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的酗捌。 我是一名探鬼主播呢诬,決...
    沈念sama閱讀 40,190評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼胖缤!你這毒婦竟也來(lái)了尚镰?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,062評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤哪廓,失蹤者是張志新(化名)和其女友劉穎狗唉,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體涡真,經(jīng)...
    沈念sama閱讀 45,500評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡分俯,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,706評(píng)論 3 335
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了哆料。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片缸剪。...
    茶點(diǎn)故事閱讀 39,834評(píng)論 1 347
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖东亦,靈堂內(nèi)的尸體忽然破棺而出杏节,到底是詐尸還是另有隱情,我是刑警寧澤典阵,帶...
    沈念sama閱讀 35,559評(píng)論 5 345
  • 正文 年R本政府宣布奋渔,位于F島的核電站,受9級(jí)特大地震影響壮啊,放射性物質(zhì)發(fā)生泄漏嫉鲸。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,167評(píng)論 3 328
  • 文/蒙蒙 一歹啼、第九天 我趴在偏房一處隱蔽的房頂上張望玄渗。 院中可真熱鬧减江,春花似錦、人聲如沸捻爷。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,779評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)也榄。三九已至巡莹,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間甜紫,已是汗流浹背降宅。 一陣腳步聲響...
    開封第一講書人閱讀 32,912評(píng)論 1 269
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留囚霸,地道東北人腰根。 一個(gè)月前我還...
    沈念sama閱讀 47,958評(píng)論 2 370
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像拓型,于是被迫代替她去往敵國(guó)和親额嘿。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,779評(píng)論 2 354