Python3簡明教程(九)—— 文件處理
文件是保存在計算機存儲設備上的一些信息或數據。你已經知道了一些不同的文件類型,比如你的音樂文件,視頻文件,文本文件。Linux 有一個思想是“一切皆文件”,這在實驗最後的 lscpu
的實現中得到了體現。Python 給了你一些簡單的方式操縱文件。
通常我們把文件分為兩類,文本文件和二進制文件。文本文件是簡單的文本,二進制文件包含了只有計算機可讀的二進制數據。
文件操作
文件打開
我們使用 open()
函數打開文件。它需要兩個參數,第一個參數是文件路徑或文件名,第二個是文件的打開模式。模式通常是下面這樣的:
"r"
,以只讀模式打開,你只能讀取文件但不能編輯/刪除文件的任何內容"w"
,以寫入模式打開,如果文件存在將會刪除裏面的所有內容,然後打開這個文件進行寫入"a"
,以追加模式打開,寫入到文件中的任何數據將自動添加到末尾
默認的模式為只讀模式,也就是說如果你不提供任何模式,open()
函數將會以只讀模式打開文件。
假設當前目錄下已有sample.py文檔,然後進入Python3打開這個文檔:
>>> fobj = open("sample.txt") >>> fobj <_io.TextIOWrapper name=‘sample.txt‘ mode=‘r‘ encoding=‘UTF-8‘>
文件關閉
打開文件後我們應該總是關閉文件。我們使用方法 close()
完成這個操作。
>>> fobj.close()
始終確保你顯式關閉每個打開的文件,一旦它的工作完成你沒有任何理由保持打開文件。因為程序能打開的文件數量是有上限的。如果你超出了這個限制,沒有任何可靠的方法恢復,因此程序可能會崩潰。
每個打開的文件關聯的數據結構(文件描述符/句柄/文件鎖...)都要消耗一些主存資源。因此如果許多打開的文件沒用了你可以結束大量的內存浪費,並且文件打開時始終存在數據損壞或丟失的可能性。
文件讀取
使用 read()
方法一次性讀取整個文件。
>>> fobj = open("sample.txt") >>> fobj.read() ‘I love Python\nI love shiyanlou\n‘ >>> fobj.close()
如果你再一次調用 read()
,它會返回空字符串因為它已經讀取完整個文件。
read(size) 有一個可選的參數 size
,用於指定字符串長度。如果沒有指定 size
或者指定為負數,就會讀取並返回整個文件。當文件大小為當前機器內存兩倍時,就會產生問題。反之,會盡可能按比較大的 size 讀取和返回數據。
readline() 能幫助你每次讀取文件的一行。
>>> fobj = open("sample.txt") >>> fobj.readline() ‘I love Python\n‘ >>> fobj.readline() ‘I love shiyanlou\n‘ >>> fobj.close()
使用 readlines()
方法讀取所有行到一個列表中。
>>> fobj = open(‘sample.txt‘) >>> fobj.readlines() [‘I love Python\n‘, ‘I love shiyanlou\n‘] >>> fobj.close()
你可以循環遍歷文件對象來讀取文件中的每一行。
>>> fobj = open(‘sample.txt‘) >>> for x in fobj: ... print(x, end = ‘‘) ... I love Python I love shiyanlou >>> fobj.close()
讓我們寫一個程序,這個程序接受用戶輸入的字符串作為將要讀取的文件的文件名,並且在屏幕上打印文件內容。
#!/usr/bin/env python3 name = input("Enter the file name: ") fobj = open(name) print(fobj.read()) fobj.close()
運行程序:
$ cd /home/shiyanlou $ chmod +x test.py $ ./test.py Enter the file name: sample.txt I love Python I love shiyanlou
文件寫入
讓我們通過 write()
方法打開一個文件然後我們隨便寫入一些文本。
>>> fobj = open("ircnicks.txt", ‘w‘) >>> fobj.write(‘powerpork\n‘) >>> fobj.write(‘indrag\n‘) >>> fobj.write(‘mishti\n‘) >>> fobj.write(‘sankarshan‘) >>> fobj.close()
現在讀取我們剛剛創建的文件:
>>> fobj = open(‘ircnicks.txt‘) >>> s = fobj.read() >>> fobj.close() >>> print(s) powerpork indrag mishti sankarshan
文件操作示例程序
1、拷貝文件程序
在這個例子裏我們拷貝給定的文本文件到另一個給定的文本文件。
#!/usr/bin/env python3 import sys if len(sys.argv) < 3: print("Wrong parameter") print("./copyfile.py file1 file2") sys.exit(1) f1 = open(sys.argv[1]) s = f1.read() f1.close() f2 = open(sys.argv[2], ‘w‘) f2.write(s) f2.close()
運行程序:
shiyanlou:~/ $ ./copyfile.py sample.txt sample2.txt shiyanlou:~/ $ ll 總用量 20K lrwxrwxrwx 1 shiyanlou shiyanlou 10 6月 9 2018 anaconda3 -> /anac onda3 drwxrwxr-x 2 shiyanlou shiyanlou 4.0K 6月 9 2018 Code -rwxrwxr-x 1 shiyanlou shiyanlou 239 2月 14 20:05 copyfile.py drwxr-xr-x 2 shiyanlou shiyanlou 4.0K 6月 9 2018 Desktop -rw-rw-r-- 1 shiyanlou shiyanlou 31 2月 14 20:06 sample2.txt -rw-rw-r-- 1 shiyanlou shiyanlou 33 8月 8 2016 sample.txt
你可以看到我們在這裏使用了一個新模塊 sys
。sys.argv
包含所有命令行參數。這個程序的功能完全可以使用 shell 的 cp
命令替代:在 cp
後首先輸入被拷貝的文件的文件名,然後輸入新文件名。
sys.argv 的第一個值是命令自身的名字,下面這個程序打印命令行參數。
#!/usr/bin/env python3 import sys print("First value", sys.argv[0]) print("All values") for i, x in enumerate(sys.argv): print(i, x)
運行程序:
$ ./argvtest.py Hi there First value ./argvtest.py All values 0 ./argvtest.py 1 Hi 2 there
這裏我們用到了一個新函數 enumerate(iterableobject)
,在序列中循環時,索引位置和對應值可以使用它同時得到。
2、文本文件相關信息統計
讓我們試著編寫一個程序,對任意給定文本文件中的制表符、行、空格進行計數。
#!/usr/bin/env python3 import os import sys def parse_file(path): """ 分析給定文本文件,返回其空格、制表符、行的相關信息 :arg path: 要分析的文本文件的路徑 :return: 包含空格數、制表符數、行數的元組 """ fd = open(path) i = 0 spaces = 0 tabs = 0 for i,line in enumerate(fd): spaces += line.count(‘ ‘) tabs += line.count(‘\t‘) # 現在關閉打開的文件 fd.close() # 以元組形式返回結果 return spaces, tabs, i + 1 def main(path): """ 函數用於打印文件分析結果 :arg path: 要分析的文本文件的路徑 :return: 若文件存在則為 True,否則 False """ if os.path.exists(path): spaces, tabs, lines = parse_file(path) print("Spaces {}. tabs {}. lines {}".format(spaces, tabs, lines)) return True else: return False if __name__ == ‘__main__‘: if len(sys.argv) > 1: main(sys.argv[1]) else: sys.exit(-1) sys.exit(0)
你可以看到程序有兩個函數,main()
和 parse_file()
,parse_file
函數真正的分析文件並返回結果,然後在 main()
函數裏打印結果。
通過分割代碼到一些更小的單元(函數)裏,能幫助我們組織代碼庫並且也更容易為函數編寫測試用例。
使用with語句
在實際情況中,我們應該嘗試使用 with
語句處理文件對象,它會在文件用完後會自動關閉,就算發生異常也沒關系。它是 try-finally 塊的簡寫:
>>> with open(‘sample.txt‘) as fobj: ... for line in fobj: ... print(line, end = ‘‘) ... I love Python I love shiyanlou
綜合示例——實現lscpu命令
在 Linux 下你可以使用 lscpu
命令來查看當前電腦的 CPU 相關信息,如下圖:
實際上 lscpu
命令是讀取 /proc/cpuinfo
這個文件的信息並美化輸出,現在你可以自己寫一個 Python 程序以只讀模式讀取 /proc/cpuinfo
這個文件,然後打印出來,這樣你就有自己的一個 Python 版本的 lscpu
命令了 :)
記得一行一行的讀取文本文件,不要一次性讀取整個文件,因為有時候你讀取的文件可能比可用內存還大。
參考鏈接:https://www.shiyanlou.com/courses/596
Python3簡明教程(九)—— 文件處理