一、文件對象
文件對象是Python代碼訪問、操作磁盤上文件的主要接口者疤。文件對象不僅可以用來訪問普通的磁盤文件,而且也可以訪問任何其它類型抽象層面上的 "文件"叠赦。一旦設(shè)置了合適的"鉤子"驹马,你就可以訪問具有文件類型接口的其它對象,就好像訪問的是普通文件一樣除秀。進(jìn)行這種抽象處理的主要原因是許多的輸入/輸出數(shù)據(jù)結(jié)構(gòu)更趨向于使用通用的接口糯累。這樣就可以在程序行為和實(shí)現(xiàn)上保持一致性。
文件只是連續(xù)的字節(jié)序列(字符串)册踩,數(shù)據(jù)的傳輸經(jīng)常會用到字節(jié)流泳姐,無論字節(jié)流是由單個字節(jié)還是大塊數(shù)據(jù)組成。對Python而言暂吉,文件的內(nèi)容總是字符串胖秒,無論文件包含的數(shù)據(jù)是什么類型。
二慕的、內(nèi)建函數(shù) open()
沒有特定的常量語法(也就是想創(chuàng)建列表那樣使用符號表達(dá)式 [ ]
)創(chuàng)建文件對象阎肝。要創(chuàng)建一個文件對象,需要調(diào)用內(nèi)建函數(shù) open() 肮街,內(nèi)建函數(shù) open() 提供了初始化輸入/輸出(I/O)操作的通用接口风题。 open() 內(nèi)建函數(shù)成功打開文件后時候會返回一個文件對象,對該文件進(jìn)行后繼相關(guān)的操作都要用到這個對象嫉父,打開不成功會引發(fā)一個 IOError
異常沛硅。成功返回的文件對象可以作為計(jì)算機(jī)上的一個文件鏈接,你可以通過調(diào)用返回的文件對象的方法來讀寫相關(guān)外部文件熔号。
內(nèi)建函數(shù) open() 的基本語法是:
file = open( file, mode='r', buffering=-1, encoding=None, errors=None, newline=None, closefd=True, opener=None )
file 是包含要打開的文件名字的字符串稽鞭,它可以是相對路徑或者絕對路徑鸟整。沒有目錄路徑時引镊,文件假定存在于當(dāng)前的工作目錄中(也就是腳本運(yùn)行的地方)。
可選變量 mode 也是一個字符串篮条,代表文件打開的模式弟头,默認(rèn)為 'r'
。通常涉茧,文件使用模式 'r'
赴恨,'w'
,或是 'a'
模式來打開伴栓,分別代表讀取伦连,寫入和追加雨饺。還有個 'U'
模式,代表通用換行符支持惑淳。在模式字符串尾部加上 'b'
额港,可以進(jìn)行二進(jìn)制數(shù)據(jù)處理。加上 '+'
意味著同時以讀寫模式打開文件歧焦。
使用 'r' 或 'U' 模式打開的文件必須是已經(jīng)存在的移斩。使用 'w' 模式打開的文件若存在則首先清空,然后(重新)創(chuàng)建绢馍。以 'a' 模式打開的文件是為追加數(shù)據(jù)作準(zhǔn)備的向瓷,所有寫入的數(shù)據(jù)都將追加到文件的末尾,即使你 seek 到了其它的地方舰涌。如果文件不存在猖任,將被自動創(chuàng)建,類似以 'w' 模式打開文件瓷耙。
另外一個可選參數(shù) buffering 用于指示訪問文件所采用的緩沖方式超升。其中 0
表示不緩沖,1
表示只緩沖一行數(shù)據(jù)哺徊,任何其它大于 1 的值代表使用給定值作為緩沖區(qū)大小室琢。不提供該參數(shù)或者給定負(fù)值代表使用系統(tǒng)默認(rèn)緩沖機(jī)制,既對任何類電報(bào)機(jī)( tty )設(shè)備使用行緩沖落追,其它設(shè)備使用正常緩沖盈滴。一般情況下使用系統(tǒng)默認(rèn)方式即可。
encoding 參數(shù)可以指定我們打開文件所使用的編碼方式轿钠,比如 utf-8 或者 gbk巢钓。請保證使用文件本身的編碼方式打開,否則會出現(xiàn)亂碼疗垛,二進(jìn)制文件默認(rèn)生成 bytes 字符串類型症汹,不能指定 encoding 參數(shù)。
如果你不知道文件的編碼贷腕,可以使用第三方的 chardet 模塊的 detect() 函數(shù)來幫助推測文件的編碼格式背镇。使用detect() 函數(shù),你需要首先使用 ‘rb'模式也就是以二進(jìn)制模型打開文件泽裳,然后文件中讀取的bytes格式的字符串傳遞給detect()函數(shù)瞒斩,detect() 函數(shù)會將推測的結(jié)果作為函數(shù)的結(jié)果返回。
返回的 confidence 指出了判斷的準(zhǔn)確程度涮总,encoding指出了這個函數(shù)判斷的文件的編碼格式胸囱。
文件對象的訪問模式
文件模式 | 操作 |
---|---|
r | 以只讀方式打開 |
rU | 或 Ua 以讀方式打開, 同時提供通用換行符支持 (PEP 278) |
w | 以寫方式打開 ,如果文件存在就先清空文件瀑梗,如果不存在就創(chuàng)建新文件 |
a | 以追加模式打開 (從 EOF 開始, 必要時創(chuàng)建新文件) |
+ | 以讀寫模式打開 |
w+ | 以讀寫模式打開 (參見 w ) |
a+ | 以讀寫模式打開 (參見 a ) |
rb | 以二進(jìn)制讀模式打開 |
wb | 以二進(jìn)制寫模式打開 (參見 w ) |
ab | 以二進(jìn)制追加模式打開 (參見 a ) |
rb+ | 以二進(jìn)制讀寫模式打開 (參見 r+ ) |
wb+ | 以二進(jìn)制讀寫模式打開 (參見 w+ ) |
ab+ | 以二進(jìn)制讀寫模式打開 (參見 a+ ) |
x | 文件存在報(bào)錯烹笔,不存在就創(chuàng)建寫內(nèi)容 |
這里是一些打開文件的例子:
fp = open('/etc/motd') # 以讀方式打開
fp = open('test', 'w') # 以寫方式打開
fp = open('data', 'r+') # 以讀寫方式打開
fp = open(r'c:\io.sys', 'rb') # 以二進(jìn)制讀模式打開
在任何情況下裳扯,Python程序中處理的文本格式文件都采用字符串的形式。讀取文件時會返回字符串形式的文本谤职,文本作為字符串傳遞給 write() 方法嚎朽。Python不會主動把對象轉(zhuǎn)換為字符串——你必須傳遞一個已經(jīng)格式化的字符串。
文本文件和二進(jìn)制文件
在Python 3中文件類型都由 open() 函數(shù)的第二個參數(shù)決定柬帕,模式字符串包含一個 'b' 表示以二進(jìn)制格式打開哟忍。Python總是支持文本文件和二進(jìn)制文件。文本文件把內(nèi)容表示為常規(guī)的 str 字符串陷寝,自動執(zhí)行 Unicode 編碼和解碼锅很,并且默認(rèn)執(zhí)行末行轉(zhuǎn)換。二進(jìn)制文件把內(nèi)容表示為一個特殊的 bytes 字符串類型凤跑,并且允許程序不修改的訪問文件內(nèi)容爆安。
通常,你必須使用 bytes 字符串處理二進(jìn)制文件仔引,使用常規(guī)的 str 字符串處理文本文件扔仓。此外,由于文本文件實(shí)現(xiàn)了Unicode編碼咖耘,不能以文本模式打開一個二進(jìn)制數(shù)據(jù)文件翘簇,這樣會將其內(nèi)容解碼為Unicode文本,生成亂碼儿倒,導(dǎo)致失敗版保。此外二進(jìn)制模式不會對數(shù)據(jù)執(zhí)行任何末行轉(zhuǎn)換,他直接讀取硬盤中文件保存的二進(jìn)制(0101)并以十六進(jìn)制的格式顯示夫否。
通用換行符支持(UNS)
不同平臺用來表示行結(jié)束的符號是不同的彻犁,例如 \n,\r凰慈,或者 \r\n汞幢。所以,Python 的解釋器也要處理這樣的任務(wù)微谓,特別是在導(dǎo)入模塊時分外重要森篷。
這就是 UNS 的關(guān)鍵所在,作為 PEP 278 的結(jié)果堰酿,Python 2.3 引入了 UNS疾宏。當(dāng)你使用 'U' 標(biāo)志打開文件的時候张足,所有的行分割符(或行結(jié)束符触创,無論它原來是什么)通過 Python 的輸入方法(例如 read*() )返回時都會被替換為換行符 NEWLINE(\n)。('rU' 模式也支持 'rb' 選項(xiàng)) 为牍。這個特性還支持包含不同類型行結(jié)束符的文件哼绑。文件對象的 newlines 屬性會記錄它曾“看到的”文件的行結(jié)束符岩馍。
如果文件剛被打開,程序還沒有遇到行結(jié)束符抖韩,那么文件的 newlines 為 None蛀恩。在第一行被讀取后,它被設(shè)置為第一行的結(jié)束符茂浮。如果遇到其它類型的行結(jié)束符双谆,文件的 newlines 會成為一個包含每種格式的元組。注意 UNS 只用于讀取文本文件席揽。沒有對應(yīng)的處理文件輸出的方法。在編譯 Python 的時候,UNS 默認(rèn)是打開的均唉。如果你不需要這個特性癌淮,在運(yùn)行 configure 腳本時,你可以使用 --without-universal-newlines 開關(guān)關(guān)閉它属桦。如果你非要自己處理行結(jié)束符熊痴,使用 os 模塊的相關(guān)屬性。
使用 with open 打開文件聂宾,代碼塊執(zhí)行完果善,文件都自動關(guān)閉
三、文件對象的內(nèi)建方法
open() 成功執(zhí)行并返回一個文件對象之后系谐,所有對該文件的后續(xù)操作都將通過這個"句柄"(文件對象)進(jìn)行岭埠。文件方法可以分為四類:輸入,輸出蔚鸥,文件內(nèi)移動惜论,以及雜項(xiàng)操作。
1止喷、輸入
read(self, n: int = -1) -> AnyStr
readline(self, limit: int = -1) -> AnyStr
readlines(self, hint: int = -1) -> List[AnyStr]
read() 方法用來直接讀取文件對象并返回字符串馆类,最多讀取給定數(shù)目個字符(注意不是字節(jié))。如果沒有給定 n 參數(shù)(默認(rèn)值為 -1)或者 n 值為負(fù)弹谁,文件將被讀取直至末尾乾巧。
readline() 方法讀取打開文件的一行(讀取下個行結(jié)束符之前的所有字節(jié))。然后整行(包括行結(jié)束符)作為字符串返回预愤。和 read() 相同沟于,它也有一個可選的 limit 參數(shù),默認(rèn)為 -1植康,代表讀至行結(jié)束符旷太。如果提供了該參數(shù),那么在超過 limit 個字節(jié)后會返回不完整的行。
readlines() 方法并不像其它兩個輸入方法一樣返回一個字符串供璧。它會讀取所有(剩余的)行然后把它們作為一個字符串列表返回存崖。它的可選參數(shù)hint 代表返回的最大字節(jié)大小。如果它大于 0 睡毒,那么返回的所有行應(yīng)該大約有 hint 字節(jié)(可能稍微大于這個數(shù)字来惧,因?yàn)樾枰獪慅R緩沖區(qū)大小)。
2演顾、輸出
write(self, s: AnyStr) -> int
writelines(self, lines: List[AnyStr]) -> None
write() 內(nèi)建方法功能與 read() 和 readline() 相反供搀。它把含有文本數(shù)據(jù)或二進(jìn)制數(shù)據(jù)塊的字符串寫入到文件中去。
和 readlines() 一樣钠至,writelines() 方法是針對列表的操作趁曼,它接受一個字符串列表作為參數(shù),將 它 們 寫 入 文 件棕洋。行 結(jié) 束 符 并 不 會 被 自 動 加 入挡闰,所 以 如 果 需 要 的 話,你 必 須 在 調(diào) 用 writelines() 前給每行結(jié)尾加上行結(jié)束符掰盘。
注意這里并沒有 "writeline()" 方法摄悯,因?yàn)樗葍r于使用以行結(jié)束符結(jié)尾的單行字符串調(diào)用 write() 方法。
3愧捕、判斷是否可讀可寫
readable(self) -> bool
writable(self) -> bool
在Linux系統(tǒng)中一切皆文件奢驯,包括硬件設(shè)備都虛擬成一個文件,但是有些文件是不可讀次绘,所以我們可以使用 readable() 方法瘪阁,判斷文件是否可讀。
我們可以使用 writable() 方法來判斷一個文件對象是否可寫邮偎。
4管跺、文件內(nèi)移動
seek(self, offset: int, whence: int = 0) -> int
seekable(self) -> bool
tell(self) -> int
seek() 方法(類似 C 中的 fseek() 函數(shù))可以在文件中移動文件指針到不同的位置。offset 字節(jié)代表相對于某個位置偏移量禾进,offset 指定的是字節(jié)數(shù)豁跑,acsii 編碼一個字母為1個字節(jié),gbk 編碼一個漢字為2個字節(jié)泻云,utf-8 編碼一個漢字為3個字節(jié)艇拍。whence 參數(shù)為位置,默認(rèn)值為 0宠纯,代表從文件開頭算起(即絕對偏移量)卸夕,1 代表從當(dāng)前位置算起,2 代表從文件末尾算起婆瓜。注意:在文本文件中快集,沒有使用 b 模式選項(xiàng)打開的文件,只允許從文件頭開始計(jì)算相對位置,從其他位置計(jì)算時就會引發(fā)異常碍讨。如果你是一個 C 程序員治力,并且使用過了 fseek()蒙秒,那么應(yīng)該知道 0勃黍,1,2 分別對應(yīng)著常量 SEEK_SET
晕讲,SEEK_CUR
覆获,以及 SEEK_END
。當(dāng)人們打開文件進(jìn)行讀寫操作的時候就會接觸到 seek()方法瓢省。
我們使用 seek() 方法在文件內(nèi)部移動弄息,使用 tell() 方法展示我們的移動過程,使用 seekable() 方法判斷文件是否可進(jìn)行 seek 操作勤婚。
5摹量、截?cái)?/h2>
truncate(self, size:int=None)->int
truncate() 默認(rèn)將當(dāng)前位置以后的字符(不包括當(dāng)前位置)截?cái)啵▌h除地方)。
6馒胆、文件迭代
如果想一行一行的掃描一個文本文件缨称,文件迭代器往往是最佳選擇。以這種方式編碼的時候祝迂,open() 臨時創(chuàng)建的文件對象將自動在每次循環(huán)迭代的時候讀入并返回一行睦尽。這種形式通常很容易編寫,對于內(nèi)存使用很好型雳,并且比其他選項(xiàng)更快(當(dāng)然根據(jù)有多少變量)当凡。
一行一行訪問文件很簡單:
for eachLine in f:
pass
在這個循環(huán)里,eachLine 代表文本文件的一行(包括末尾的行結(jié)束符)纠俭,你可以使用它做任何想做的事情沿量。
文件迭代更為高效,而且寫(和讀)這樣的 Python 代碼更容易冤荆。7欧瘪、把內(nèi)存中文件的內(nèi)容刷入到硬盤中
flush(self) -> None
調(diào)用文件對象的 flush() 方法可以把內(nèi)存中的文件的內(nèi)容寫入到硬盤中。
8匙赞、文件關(guān)閉
close(self) -> None
closed(self) -> bool
我們可以調(diào)用文件對象的 close() 方法關(guān)閉文件來結(jié)束對它的訪問佛掖。Python 垃圾收集機(jī)制也會在文件對象的引用計(jì)數(shù)降至零的時候自動關(guān)閉文件。這在文件只有一個引用時發(fā)生涌庭,例如 fp = open(...)芥被,然后 fp 在原文件顯式地關(guān)閉前被賦了另一個文件對象。良好的編程習(xí)慣要求在重新賦另個文件對象前關(guān)閉這個文件坐榆。如果你不顯式地關(guān)閉文件拴魄,那么你可能丟失輸出緩沖區(qū)的數(shù)據(jù)。默認(rèn)情況下,輸出文件總是緩沖的匹中,這意味著寫入的文本可能不會立即自動從內(nèi)存轉(zhuǎn)換到硬盤——關(guān)閉一個文件夏漱,或者運(yùn)行其 flush() 方法,迫使緩存的數(shù)據(jù)進(jìn)入硬盤顶捷。
調(diào)用 flush() 方法會直接把內(nèi)存緩沖區(qū)中的數(shù)據(jù)立刻寫入文件挂绰,而不是被動地等待輸出緩沖區(qū)被寫入。使用 closed() 方法判斷一個文件對象是否已經(jīng)關(guān)閉了服赎。
四葵蒂、標(biāo)準(zhǔn)文件
一般說來,只要你的程序一執(zhí)行重虑,那么你就可以訪問三個標(biāo)準(zhǔn)文件践付。它們分別是標(biāo)準(zhǔn)輸入(一般是鍵盤)、標(biāo)準(zhǔn)輸出(到顯示器的緩沖輸出)和標(biāo)準(zhǔn)錯誤(到屏幕的非緩沖輸出)缺厉。這里所說的"緩沖"和"非緩沖"是指 open() 函數(shù)的第三個參數(shù)永高。這些文件沿用的是 C 語言中的命名,分別為stdin提针,stdout 和 stderr命爬。我們說"只要你的程序一執(zhí)行就可以訪問這三個標(biāo)準(zhǔn)文件",意思是這些文件已經(jīng)被預(yù)先打開了关贵,只要知道它們的文件句柄就可以隨時訪問這些文件遇骑。
Python 中可以通過 sys 模塊來訪問這些文件的句柄。導(dǎo)入 sys 模塊以后揖曾,就可以使用sys.stdin落萎,sys.stdout 和 sys.stderr 訪問。print() 語句通常是輸出到 sys.stdout炭剪;而 input() 語句則通常從 sys.stdin 接受輸入练链。
五、第三方模塊
使用用pickle模塊來存儲Python的原生對象
如果你真的想存儲Python原生對象奴拦,但又無法信賴文件的數(shù)據(jù)來源媒鼓,Python標(biāo)準(zhǔn)庫pickle模塊是能夠讓我們直接在文件中存儲幾乎任何Python對象的高級工具,并不需要我們吧字符串轉(zhuǎn)換來轉(zhuǎn)換去错妖。
文件中打包二進(jìn)制數(shù)據(jù)的存儲與解析
有些高級應(yīng)用程序也需要處理打包的二進(jìn)制數(shù)據(jù)暂氯,Python的標(biāo)準(zhǔn)庫包含的struct模塊能夠構(gòu)造并解析打包的二進(jìn)制數(shù)據(jù)潮模。從某種意義上說,它是另一個數(shù)據(jù)轉(zhuǎn)換工具痴施,它能夠把文件中的字符串解讀為二進(jìn)制數(shù)據(jù)擎厢。
《Python基礎(chǔ)手冊》系列:
Python基礎(chǔ)手冊 1 —— Python語言介紹
Python基礎(chǔ)手冊 2 —— Python 環(huán)境搭建(Linux)
Python基礎(chǔ)手冊 3 —— Python解釋器
Python基礎(chǔ)手冊 4 —— 文本結(jié)構(gòu)
Python基礎(chǔ)手冊 5 —— 標(biāo)識符和關(guān)鍵字
Python基礎(chǔ)手冊 6 —— 操作符
Python基礎(chǔ)手冊 7 —— 內(nèi)建函數(shù)
Python基礎(chǔ)手冊 8 —— Python對象
Python基礎(chǔ)手冊 9 —— 數(shù)字類型
Python基礎(chǔ)手冊10 —— 序列(字符串)
Python基礎(chǔ)手冊11 —— 序列(元組&列表)
Python基礎(chǔ)手冊12 —— 序列(類型操作)
Python基礎(chǔ)手冊13 —— 映射(字典)
Python基礎(chǔ)手冊14 —— 集合
Python基礎(chǔ)手冊15 —— 解析
Python基礎(chǔ)手冊16 —— 文件
Python基礎(chǔ)手冊17 —— 簡單語句
Python基礎(chǔ)手冊18 —— 復(fù)合語句(流程控制語句)
Python基礎(chǔ)手冊19 —— 迭代器
Python基礎(chǔ)手冊20 —— 生成器
Python基礎(chǔ)手冊21 —— 函數(shù)的定義
Python基礎(chǔ)手冊22 —— 函數(shù)的參數(shù)
Python基礎(chǔ)手冊23 —— 函數(shù)的調(diào)用
Python基礎(chǔ)手冊24 —— 函數(shù)中變量的作用域
Python基礎(chǔ)手冊25 —— 裝飾器
Python基礎(chǔ)手冊26 —— 錯誤 & 異常
Python基礎(chǔ)手冊27 —— 模塊
Python基礎(chǔ)手冊28 —— 模塊的高級概念
Python基礎(chǔ)手冊29 —— 包