本文是筆者學(xué)習(xí)廖雪峰Python3教程的筆記,在此感謝廖老師的教程讓我們這些初學(xué)者能夠一步一步的進(jìn)行下去.如果讀者想學(xué)習(xí)完成的教程,請訪問廖雪峰Python3教程,筆記如有侵權(quán),請告知刪除...
讀文件
以讀文件的方式打開文件的做法是使用Python內(nèi)置的open()函數(shù),參數(shù)為文件名和標(biāo)識符
標(biāo)識符:
r 以只讀方式打開文件。文件的指針將會放在文件的開頭。這是默認(rèn)模式。
rb 以二進(jìn)制格式打開一個文件用于只讀。文件指針將會放在文件的開頭。這是默認(rèn)模式。
r+ 打開一個文件用于讀寫。文件指針將會放在文件的開頭。
rb+ 以二進(jìn)制格式打開一個文件用于讀寫。文件指針將會放在文件的開頭。
w 打開一個文件只用于寫入。如果該文件已存在則將其覆蓋。如果該文件不存在,創(chuàng)建新文件。
wb 以二進(jìn)制格式打開一個文件只用于寫入。如果該文件已存在則將其覆蓋。如果該文件不存在,創(chuàng)建新文件。
w+ 打開一個文件用于讀寫。如果該文件已存在則將其覆蓋。如果該文件不存在,創(chuàng)建新文件。
wb+ 以二進(jìn)制格式打開一個文件用于讀寫。如果該文件已存在則將其覆蓋。如果該文件不存在,創(chuàng)建新文件。
a 打開一個文件用于追加。如果該文件已存在,文件指針將會放在文件的結(jié)尾。也就是說,新的內(nèi)容將會被寫入到已有內(nèi)容之后。如果該文件不存在,創(chuàng)建新文件進(jìn)行寫入。
ab 以二進(jìn)制格式打開一個文件用于追加。如果該文件已存在,文件指針將會放在文件的結(jié)尾。也就是說,新的內(nèi)容將會被寫入到已有內(nèi)容之后。如果該文件不存在,創(chuàng)建新文件進(jìn)行寫入。
a+ 打開一個文件用于讀寫。如果該文件已存在,文件指針將會放在文件的結(jié)尾。文件打開時會是追加模式。如果該文件不存在,創(chuàng)建新文件用于讀寫。
ab+ 以二進(jìn)制格式打開一個文件用于追加。如果該文件已存在,文件指針將會放在文件的結(jié)尾。如果該文件不存在,創(chuàng)建新文件用于讀寫。
f = open('User/joe/Desktop/test1.py', 'r')
如果文件不存在的話,就會拋出一個IOError錯誤,來告訴你找不到文件.
open()打開文件之后,就可以使用read()來一次讀取全部的文件,最后需要調(diào)用close()來關(guān)閉文件.但是由于可能會出現(xiàn)IOError迫使程序運(yùn)行終止,那么就永遠(yuǎn)不會走到close()方法了.
所以,Python中提供了with()語句來自動幫我們調(diào)用close()方法.
with open('User/joe/Desktop/test1.py', 'r') as f:
f.read()
使用read()方法讀取文件的時候,是一次性打開全部的內(nèi)容,如果文件很大的話,內(nèi)存就會出現(xiàn)問題.為了保險起見,需要在read()方法中傳入一個size參數(shù),然后反復(fù)調(diào)用read()反復(fù),保證每次讀取合適大小的內(nèi)容,直到最后調(diào)用結(jié)束.除此之外,Python中提供了readlines()方法,來一行一行的讀取文件.
with open('User/joe/Desktop/test1/py', 'r') as f:
for line in f.readlines():
print(line.strip())
file-like Object
像open()函數(shù)返回的這種有個read()方法的對象,在Python中統(tǒng)稱為file-like Object.
StringIO就是在內(nèi)存中創(chuàng)建的file-like Object,常用作臨時緩沖。
-
二進(jìn)制文件
要讀取二進(jìn)制文件,比如圖片、視頻等等,用'rb'模式打開文件即可
-
字符編碼
要讀取編碼文件,需要在open()中傳入encode參數(shù),比如:
f = open('/User/joe/Desktop/test1.py', encoding = 'gbk') f.read()
寫文件
寫文件與讀文件一樣,只不過在open()的標(biāo)識符參數(shù)中傳入 'w'或者'wb'即可.
然后調(diào)用write()方法,寫出文件,最后調(diào)用close()文件關(guān)閉文件即可.
StringIO & BytesIO
很多時候讀數(shù)據(jù)不一定是從文件中讀, 還有可能從內(nèi)存中讀. 要讀取StringIO,需要先從io中導(dǎo)入StringIO.
寫入數(shù)據(jù)到StringIO中,需要先創(chuàng)建一個StringIO.然后像文件一樣寫入即可.調(diào)用getvalue()方法獲得寫入的str
from io import StringIO
f = StringIO()
f.write('Hello World')
print(f.getvalue())
從StringIO中讀數(shù)據(jù).使用str初始化一個StringIO,然后像讀文件一樣讀取數(shù)據(jù).
from io import StringIO
f = StringIO('Hello World')
f.read()
StringIO只能操作str類型的數(shù)據(jù),如果要操作二進(jìn)制數(shù)據(jù)則需要導(dǎo)入BytesIO
BytesIO實現(xiàn)了在內(nèi)存中讀寫bytes,我們創(chuàng)建一個BytesIO,然后寫入一些bytes
from io import BytesIO
f = BytesIO()
f.write('中文'.encode('utf-8'))
print(f.getvalue())
這里寫入的經(jīng)過encode編碼的二進(jìn)制數(shù)據(jù)
與StringIO類似,可以用一個bytes初始化BytesIO,然后,像讀文件一樣讀取
from io import BytesIO
f = BytesIO(b'\xe4\xb8\xad\xe6\x96\x87')
f.read()
操作文件和目錄
Python內(nèi)置的os模塊可以直接調(diào)用操作系統(tǒng)提供的接口函數(shù)來實現(xiàn)文件和目錄的操作,操作文件和目錄的函數(shù)一部分放在os模塊中,一部分放在os.path模塊中.
import os
# 查看當(dāng)前目錄的絕對路徑:
os.path.abspath('.')
'/Users/joe/Desktop'
# 在某個目錄下創(chuàng)建一個新目錄,首先把新目錄的完整路徑表示出來:
os.path.join(os.path.abspath('.'), 'testdir')
'/Users/joe/Desktop/testdir'
# 然后創(chuàng)建一個目錄:
os.mkdir('/Users/joe/Desktop/testdir')
# 刪掉一個目錄:
os.rmdir('/Users/joe/Desktop/testdir')
要拆分路徑時,也不要直接去拆字符串,而要通過os.path.split()函數(shù),這樣可以把一個路徑拆分為兩部分,后一部分總是最后級別的目錄或文件名.
os.path.split(/Users/joe/Desktop/testdir)
os.path.splitext()可以直接得到文件擴(kuò)展名.
使用rename()對文件重命名和remove()刪掉文件.
利用Python的特性來過濾文件。比如我們要列出當(dāng)前目錄下的所有目錄,只需要一行代碼:
[x for x in os.listdir('.') if os.path.isdir(x)] ['.lein', '.local', '.m2', '.npm', '.ssh', '.Trash', '.vim', 'Applications', 'Desktop', ...]
要列出所有的.py文件,也只需一行代碼:
[x for x in os.listdir('.') if os.path.isfile(x) and os.path.splitext(x)[1]=='.py'] ['apis.py', 'config.py', 'models.py', 'pymonitor.py', 'test_db.py', 'urls.py', 'wsgiapp.py']
序列化
我們把變量從內(nèi)存中變成可存儲或傳輸?shù)倪^程稱之為序列化,在Python中叫pickling.序列化之后,就可以把序列化后的內(nèi)容寫入磁盤,或者通過網(wǎng)絡(luò)傳輸?shù)絼e的機(jī)器上.反過來,把變量內(nèi)容從序列化的對象重新讀到內(nèi)存里稱之為反序列化,即unpickling。
- 序列化一個dict
import pickle
d = dict(name = 'joe', age = 24, score = 90)
pickle.dumps(d)
pickle.dumps()方法把任意對象序列化成一個bytes,然后,就可以把這個bytes寫入文件?;蛘哂昧硪粋€方法pickle.dump()直接把對象序列化后寫入一個file-like Object.
import pickle
d = dict(name = 'joe', age = 24, score = 90)
f.open('hhh.py','wb')
pickle.dump(d, f)
f.close()
hhh.py中存儲的就是dict被序列化的內(nèi)容.
當(dāng)我們要把對象從磁盤讀到內(nèi)存時,可以先把內(nèi)容讀到一個bytes,然后用pickle.loads()方法反序列化出對象,也可以直接用pickle.load()方法從一個file-like Object中直接反序列化出對象。我們打開另一個Python命令行來反序列化剛才保存的對象
f = open('hhh.py', 'rb')
d = pickle.load(f)
f.close()
這樣變量的內(nèi)容又回來,但是這個變量與之前的只是內(nèi)容相同,并不是一個變量.
JSON
Python內(nèi)置了Json模塊,將dict轉(zhuǎn)換為json的方法為:
import json
d = dict(name = 'joe', age = 24, score = 90)
json.dumps(d)
dumps()方法返回一個str,內(nèi)容就是標(biāo)準(zhǔn)的JSON.
反序列化是調(diào)用loads()方法
import json
json_str = dict(name = 'joe', age = 24, score = 90)
json.laods(json_str)
如果我們在dumps的可選參數(shù)deault中不傳入任何參數(shù),Python將無法知道怎么將一個class序列化,這時需要寫一個轉(zhuǎn)換函數(shù)來將class實例轉(zhuǎn)化為json對象.
同樣的道理,如果需要反序列化一個class,同樣需要寫一個轉(zhuǎn)換函數(shù),傳到object_hook參數(shù)中.
import json
class Studnet(object):
def __init__(self, name, age, score):
self.name = name
self.age = age
self.score = score
s = Student('Joe', 24, 90)
#要序列化s
def student2dict(std):
return {'name': std.name, 'age': std.age, 'score': std.score}
json.dumps(s, default= student2dict)
# 序列化的結(jié)果
# '{"name": "Bob", "score": 90, "age": 20}'
# 反序列化
json_str = '{"name": "Bob", "score": 90, "age": 20}'
def dict2Student:(dic):
return Student(dic['name'], dic['age'], dic['score'])
json.loads(json_str, object_hook= dict2Student)
# 反序列化的結(jié)果
#<__main__.Student object at 0x102af07f0>