讀取文件不再使用 With Open
有時我們需要把數據永久存儲起來,隨時使用隨時讀取。例如,我們通過程序建立的列表、字典等數據,當程序結束時,需要把這些數據存儲到文件中,當程序再次啟動時,可以把這些數據讀入到程序中,避免這些數據的重新錄入。
在Python語言中,負責文件操作的稱為文件對象,文件對象不僅可以訪問存儲在磁盤中的文件,也可以訪問網絡文件。文件對象通過open函數得到,獲取文件對象后,就可以使用文件對象提供的方法來讀寫文件。
但open函數在處理某些問題是并不是很理想,有沒有其他比open函數更加適合讀取某些特定文件呢?下面我們就一起來看看!
回顧open函數
對文件操作使用最頻繁對函數,open()打開一個文件對象,使用Python內置的open()函數,傳入文件名和模式。
- name: 要讀取的文件名稱。
- mode?: 打開文件的模式,選填。r, r+, w, w+, a, a+使用最多。
- buffering: 文件所需的緩沖區大小, 選填。0表示無緩沖, 1表示線路緩沖。有四種打開文件的不同方法(模式)
- "r" - 讀取 - 默認值。打開文件進行讀取,如果文件不存在則報錯。
- "a" - 追加 - 打開供追加的文件,如果不存在則創建該文件。
- "w" - 寫入 - 打開文件進行寫入,如果文件不存在則創建該文件。
- "x" - 創建 - 創建指定的文件,如果文件存在則返回錯誤。
- 此外,可以指定文件是應該作為二進制還是文本模式進行處理。
- "t" - 文本 - 默認值。文本模式。
- "b" - 二進制 - 二進制模式(例如圖像)。
使用時常通過with open()方法讀寫文件。
pathlib
以前在Python中操作文件路徑,更多的時候是使用os模塊。Python3的系統標準庫pathlib模塊的Path對路徑的操作會更簡單。
pathlib的一些基本操作,如文件名操作、路徑操作、文件操作等等并不在本文討論范圍。本此介紹使用率非常高的文件操作,其文件讀寫方法。
Path.open
在pathlib里如果要打開一個文件十分的簡單。
打開路徑指向的文件,就像內置的open()函數所做的一樣。
結果
Path讀與寫
對于簡單的文件讀寫,在pathlib模塊中有幾個簡便的方法:
- Path.read_text(): 以字符串形式返回路徑指向的文件的解碼后文本內容。
- Path.read_bytes(): 以二進制/字節模式打開路徑并以字節串的形式返回內容。
- Path.write_text(): 打開路徑并向其寫入字符串數據。
- Path.write_bytes(): 以二進制/字節模式打開路徑并向其寫入數據。
更多詳情可參見pathlib模塊[1]。
fileinput
如果你只想讀取一個文件,使用open()。如果需要實現文件列表的批量循環操作,不妨使用本模塊。
fileinput.input
input是fileinput模塊的初始接口,其使用也是較簡單。
- files 需要讀取的文件對象,可迭代對象。
- inplace 標準輸出重定向替換,表示是否將標準輸出的結果寫回文件,默認不取代。
- backup? 讀取時同時備份文件,可以指定備份的后綴名,比如 backup='.bak'。
- mode? 文件讀取模式,fileinput 有且僅有這兩種讀取模式r?和 rb。
- 默認使用mode='r'
- 如果文件是二進制的,可以使用mode='rb' 模式。
- openhook 支持用戶傳入自定義的對象讀取方法。fileinput 內置了兩個勾子函數:
- fileinput.hook_encoded(encoding, errors=None)使用gzip? 和bz2模塊透明地打開 gzip 和 bzip2 壓縮的文件
- fileinput.hook_compressed(filename, mode)使用給定的 encoding 和 errors 來讀取文件。
從標準輸入中讀取
若input()不傳任何參數時,fileinput 默認會以 stdin 作為輸入源。
運行stdinput.py后,在編譯器中輸入內容,程序會自動讀取并再打印一次。
從指定文件中讀取
讀取批量文件
輸出
由于 info.txt 和 info.txt 的內容被整合成一個文件對象 file ,因此 fileinput.lineno() 只有在讀取一個文件時,才是原文件中真實的行號。如果想要在讀取多個文件的時候,也能讀取原文件的真實行號,可以使用 fileinput.filelineno() 方法。
以上幾個常用對方法解釋如下。
- fileinput.filename()返回當前被讀取的文件名。在第一行被讀取之前,返回None。
- fileinput.lineno()返回已被讀取的累計行號。在第一行被讀取之前,返回 0。在最后一個文件的最后一行被讀取之后,返回該行的行號。
- fileinput.filelineno()返回當前文件中的行號。在第一行被讀取之前,返回 0。在最后一個文件的最后一行被讀取之后,返回此文件中該行的行號。
讀取單個文件
與批量讀取文件一樣,只需要在參數files中傳人一個文件即可。
輸出
與glob配合批量讀取
glob簡介
glob是python自帶的一個操作文件的相關模塊,可以對文件夾下所有文件進行遍歷,并將符合匹配模式的文件名保存為一個list列表。
返回匹配 pathname 的可能為空的路徑名列表,其中的元素必須為包含路徑信息的字符串。
pathname 可以是絕對路徑 (如 /usr/src/Tools/sub/1.gif) 或相對路徑 (如 ../../Tools/*/*.gif),并且可包含 shell 風格的通配符。
實例
一個包含以下內容的目錄:文件 1.gif, 2.txt, card.gif 以及一個子目錄 sub 其中只包含一個文件 3.txt。glob()將產生如下結果。請注意路徑的任何開頭部分都將被保留。
fileinput與glob配合使用
輸出
更多使用方法請參見 fileinput模塊[2]。
codecs
常用open方法操作文件,寫入str類型,不管字符串是什么編碼方式,此時一般不會出現什么問題。但有時候我們爬蟲或者其他方式得到一些數據寫入文件時會有編碼不統一的問題,或在自然語言處理過程中,使用open方法操作文件會經常出現報錯,通常是編碼錯誤。
此時如若想繼續使用 open 方式打開,就需要先將輸入文件decode,統一轉為unicode ,再encode到目標編碼方式,如gbk、utf-8等等。即
幸運的是,可以使用 codecs.open() 代替這一繁瑣操作。這種方法可以指定一個編碼打開文件,讀取返回的將是unicode。
codecs.open()
使用給定的 mode 打開已編碼的文件并返回一個 StreamReaderWriter 的實例,提供透明的編碼/解碼。
mode參數可以是內置 open()函數所接受的任意二進制模式,默認的文件模式為 'r',表示以讀取模式打開文件。'b' 會被自動添加。
encoding指定文件所要使用的編碼格式。允許任何編碼為字節串或從字節串解碼的編碼格式,而文件方法所支持的數據類型則取決于所使用的編解碼器。
寫入時,如果參數是unicode,則使用open()時指定的編碼進行編碼后寫入;如果是str,則先根據源代碼文件聲明的字符編碼,解碼成unicode后再進行前述操作。
相對內置的open()來說,這個方法比較不容易在編碼上出現問題,并且在速度不變的同時,還兼容open()函數所有操作命令。
應用實例
將未知編碼方式的csv文件轉為utf-8格式文件。
更多相關方法可參見**codecs模塊[3]**。
CSV
CSV[4] (Comma Separated Values),即逗號分隔值(也稱字符分隔值,因為分隔符可以不是逗號),是一種常用的文本格式,用以存儲表格數據,包括數字或者字符。很多程序在處理數據時都會碰到csv這種格式的文件。
python內置了csv模塊。常用的有四個方法:
csv.reader
返回一個reader對象,該對象將逐行遍歷csvfile 。
svfile可以是任何對象,文件對象和列表對象均適用。如果 csvfile 是文件對象,則打開它時應使用 newline=''。
dialect用于不同的 CSV 變種的特定參數組。
fmtparams可以覆寫當前變種格式中的單個格式設置。有關變種和格式設置參數的完整詳細信息,請參見 變種與格式參數[5] 。
應用實例
輸出
以上用到的變種與格式參數解釋如下。
delimiter一個用于分隔字段的單字符,默認為 ' , '。
quotechar一個單字符,用于包住含有特殊字符的字段,特殊字符如 定界符 或 引號字符 或 換行符。默認為 ' " '。
由于使用 open()來讀取 CSV 文件,因此默認情況下,將使用系統默認編碼來解碼文件并轉換為unicode,要使用其他編碼來解碼文件,可使用open的encoding參數:
csv.writer
返回一個 writer 對象,該對象將用戶的數據在給定的文件類對象上轉換為帶分隔符的字符串。None 值會寫入為空字符串。
寫入前,所有非字符串數據都先用 str() 轉化為字符串再寫入。
csvfile 可以是具有 write() 方法的任何對象。
應用案例
輸出csv文件打開如下
參數quoting說明:控制 writer 何時生成引號,以及 reader 何時識別引號。該屬性可以等于任何 QUOTE_* 常量,默認為QUOTE_MINIMAL。
QUOTE_\* 常量包括:
csv.QUOTE_ALL指示writer 對象給所有字段加上引號。
csv.QUOTE_MINIMAL指示writer 對象僅為包含特殊字符(例如定界符、引號字符或行結束符中的任何字符)的字段加上引號。
csv.QUOTE_NONNUMERIC指示writer 對象為所有非數字字段加上引號。指示reader 將所有未用引號引出的字段轉換為float 類型。
csv.QUOTE_NONE指示writer 對象不使用引號引出字段。當定界符出現在輸出數據中時,其前面應該有轉義符。如果未設置轉義符,則遇到任何需要轉義的字符時,writer 都會拋出 Error 異常。指示reader 不對引號字符進行特殊處理。
csv.DictReader
創建一個對象,該對象在操作上類似于常規 reader,但是將每行中的信息映射到一個 dict,該 dict 的鍵由 fieldnames 可選參數給出。
fieldnames參數是一個 sequence。如果省略 **fieldnames**,則文件 f 第一行中的值將用作字段名。無論字段名是如何確定的,字典都將保留其原始順序。
如果某一行中的字段多于字段名,則剩余數據會被放入一個列表,并與 restkey 所指定的字段名 (默認為 None) 一起保存。如果某個非空白行的字段少于字段名,則缺失的值會使用 restval 的值來填充 (默認為 None)。
應用實例
注意:
在 3.6 版更改: 返回的行現在的類型是 OrderedDict。在 3.8 版更改: 現在,返回的行是 dict類型。
python 3.6/3.7輸出:
python 3.8輸出
Reader 對象的一些方法
csvreader.line_num源迭代器已經讀取了的行數。它與返回的記錄數不同,因為記錄可能跨越多行。
csvreader.fieldnames字段名稱。如果在創建對象時未傳入字段名稱,則首次訪問時或從文件中讀取第一條記錄時會初始化此屬性。
輸出
csv.DictWriter
創建一個對象,該對象在操作上類似常規 writer,但會將字典映射到輸出行。
fieldnames 參數是由鍵組成的 sequence,它指定字典中值的順序,這些值會按指定順序傳遞給 writerow() 方法并寫入文件 f 。
如果字典缺少 fieldnames 中的鍵,則可選參數 restval 用于指定要寫入的值。
如果傳遞給 writerow() 方法的字典的某些鍵在 fieldnames 中找不到,則可選參數 extrasaction 用于指定要執行的操作。如果將其設置為默認值 'raise',則會引發 ValueError。如果將其設置為 'ignore',則字典中的其他鍵值將被忽略。
應用案例
寫入的csv文件打開結果如下
Writer 對象的一些方法
DictWriter.writeheader()在 writer 的文件對象中,寫入一行字段名稱(字段名稱在構造函數中指定),并根據當前設置的變種進行格式化。
csvwriter.writerow(row)將參數 row 寫入 writer 的文件對象。
csvwriter.writerows(rows)將 rows (即能迭代出多個上述 row 對象的迭代器)中的所有元素寫入 writer 的文件對象
更多相關方法可參見csv模塊[6]。
第三方模塊
另外還有專門針對Word文件、Excel文件及PDF文件的模塊,這里只簡單介紹下。
word文件
python-docx
PDF文件
pdfplumber
Excel文件
比較常用的Excel操作模塊有如下三種。
- xlrd 讀取.xls和.xlsx文件
- xlwings 讀取.xls和.xlsx文件
- openpyxl 讀取.xlsx文件
xlrd
xlrd不能創建和保存Excel文件
xlwings
xlwings 直接對接的是 Excel 應用程序,然后才是工作簿 books 和工作表 sheets,xlwings 需要安裝有 Excel 應用程序的環境xlwings 可以讀取 .xls 和 .xlsx 文件。
openpyxl
openpyxl 可以讀取 .xlsx 文件,如果讀取.xls 文件會報錯。
另外還有很強大的pandas模塊,具體可參見Python數據分析實戰之數據獲取三大招,本文不在贅述。
參考資料
[1]pathlib模塊: https://docs.python.org/zh-cn/3/library/pathlib.html
[2]fileinput模塊: https://docs.python.org/zh-cn/3/library/fileinput.html
[3]codecs模塊: https://docs.python.org/zh-cn/3/library/codecs.html
[4]CSV: http://zh.wikipedia.org/zh-cn/逗號分隔值
[5]變種與格式參數: https://docs.python.org/zh-cn/3/library/csv.html#csv-fmt-params
[6]csv模塊: https://docs.python.org/zh-cn/3/library/csv.html#index-0