題目
本題本題開始涉及文件的操作,文件操作是一件危險的事情,需要仔細細心否則可能導致重要的文件損壞。
本題除了 ex15.py
這個腳本以外,還需要一個用來讀取的文件 ex15_sample.txt
其內容如下:
This is stuff I typed into a file.
It is really cool stuff.
Lots and lots of fun to have in here.
我們需要用 python 腳本打開文件並打印出來,不過我們不能把 ex15_sample.txt
寫死在腳本中,而是要利用之前聯繫過的 argv
和 input
從用戶那裏得知要處理的文件名。
加分練習
本題的難度跨度略大,因此 Zed 建議我們盡力做好加分練習後再做後面的練習。
- 在每行上面加註釋說明用途。
- 如果不確定答案,就找人問問,或者利用搜索(比如 “python open”)
- Zed 在本題中用了了”命令“這個詞,其實它們是“函數”和“方法”,去試着瞭解它們。
- 刪除 16-24 行(以我的答案)用到的
input
部分,再次運行一遍腳本。 - 只用
input
寫這個腳本,思考那種得到文件名的方法更好?爲什麼? - 運行
pydoc file
找到read()
命令(函數/方法),會看到很多別的命令,找幾條試試。不需要看__
(雙下劃線)的命令,這些只是垃圾而已(?) - 再次運行 python 命令行,在命令行下使用
open
打開文件,這種 open 和 read 的方法值得也學習一下。 - 讓腳本針對
txt
和txt_again
變量執行一下close()
,處理完成的文件需要關閉,這點很重要。
我的答案
15.0 基礎練習 + 15.1 註釋
# 載入 sys.argv 模塊,以獲取腳本運行參數。
from sys import argv
# 將 argv 解包,並將腳本名賦值給變量 script ;將參數賦值給變量 filename 。
script, filename = argv
# 將名爲 “filename” 的文件打開,並將打開的內容賦值給變量 txt
txt = open(filename)
# 打印文件名,並在讀取文件內容後打印
print("Here's youer file %r:" % filename)
print(txt.read())
# ------------上面是通過 argv 獲取文件名--------
# 以 input 方式讓用戶在腳本運行後輸入文件名
print("Type the filename again:")
file_again = input("> ")
# 打開用戶輸入的文件
txt_again = open(file_again)
# 讀取後打印用戶輸入文件的內容
print(txt_again.read())
1-6 行使用 argv
我們相對都比較熟悉了。
open
是一個新的東西,我們可以通過 pydoc open
查看它的說明,恰巧發現有“友猿”整理了一部分 open 中文版文檔 少做排版、補充如下:
open(file, mode=’r’, buffering=-1, encoding=None, errors=None, newline=None, closefd=True, opener=None)
(在使用該函數的時候,除了file參數必填外,其他參數可以選用。在本代碼中對其他參數使用了默認值。)
在使用 open() 的時候,如果文件不存在,那麼將會返回 IOError。
參數說明:
file
:文件名稱;
mode
:制定了文件打開的方式,函數提供瞭如下方式,其中,’rt’爲默認方式。
mode參數 解釋 中文 指針位置 'r'
open for reading (default) 只讀,默認方式 開頭 'w'
open for writing, truncating the file first 寫入,會覆蓋源文件內容 開頭 'x'
create a new file and open it for writing 創建新文件,並寫入內容,如果文件已存在,將會報錯:FileExistsError 開頭 'a'
open for writing, appending to the end of the file if it exists 寫入,如果文件有內容,則在末尾追加寫入 末尾 'b'
binary mode 二進制模式 't'
text mode (default) 文本模式 '+'
open a disk file for updating (reading and writing) 更新磁盤文件,讀寫 'U'
universal newline mode (deprecated) 在paython3中已經棄用
buffering
:用於設置緩存策略
在二進制模式下,使用0來切換緩衝;在文本模式下,通過1表示行緩衝(固定大小的緩衝區)。
在不給參數的時候,二進制文件的緩衝區大小由底層設備決定,可以通過io.DEFAULT_BUFFER_SIZE獲取,通常爲4096或8192字節
文本文件則採用行緩衝。
encoding
:編碼或者解碼方式。默認編碼方式依賴平臺,如果需要特殊設置,可以參考codecs模塊,獲取編碼列表。
errors
:可選,並且不能用於二進制模式,指定了編碼錯誤的處理方式,可以通過codecs.Codec獲得編碼錯誤字符串
newline
:換行控制(僅適用於文本模式),參數有:None,’\n’,’\r’,’\r\n’。
輸入時,如果參數爲None,那麼行結束的標誌可以是:’\n’,’\r’,’\r\n’任意一個,並且三個控制符都首先會被轉化爲:’\n’,然後纔會被調用;
如果參數爲''
,所有的通用的換行結束標誌都可以用,但是行結束標識符返回調用不會被編碼。
輸出時,如果參數爲None,那麼行結束的標誌可以是:’\n’被轉換爲系統默認的分隔符;如果是”,’\n’則不會被編碼。
如果closefd = False
,則在文件關閉時,底層文件描述符將保持打開狀態。 這在給定文件名時不起作用,在這種情況下必須爲True。
opener
:可以通過調用*opener*
方式,使用自定義的開啓器。底層文件描述符是通過調用*opener*
或者*file*
,*flags*
獲得的。
*opener*
必須返回一個打開的文件描述。將os.open
作爲*opener*
的結果,在功能上,類似於通過None。===以下來自谷歌機翻===
open()
返回一個文件對象,其類型取決於模式,並通過它執行標準文件操作,如讀和寫。
當使用open()
以文本模式(’w’,’r’,’wt’,’rt’等)打開文件時,它將返回一個TextIOWrapper。 當用於以二進制模式打開文件時,返回的類會有所不同:在讀取二進制模式下,它將返回一個BufferedReader; 在寫入二進制文件和追加二進制模式時,它返回一個BufferedWriter,並且在讀/寫模式下,它返回一個BufferedRandom。也可以使用字符串或字節陣列作爲讀取和寫入的文件。 對於字符串StringIO可以像在文本模式下打開的文件一樣使用,對於字節,可以使用BytesIO就像以二進制模式打開的文件一樣。
我們把 open 打開的文件賦值給了變量 txt
。
接着在打印了一句話後,在第 12 行我們在 txt
這個被 open 打開的 file
(“文件”類型)類型的變量上使用英文句號 .
調用了一個命令 read
,並且麼有在括號中傳遞任何參數。
句點 A.B
是 python 常用的調用函數或方法,其意義相當於調用 A 下擁有的 B 方法。所有在本題的意思大概就是說“嘿 txt!你有一個‘方法’是 read吧?執行它,不需要任何參數”。
15.3 函數和方法
函數和方法是很相似的東西,因爲長的很像,所有有不少人覺得就是一個東西。
先來說一下各種語言都有的函數,函數是一組可以重複執行實現一個或一些功能的代碼。例如 print()
實現了把參數內容打印出來的功能,而且反覆執行功能維持不變。
方法則涉及類的概念,類中會有函數,實現類的一些功能,類的功能叫做類的方法。
15.4 刪除 input
我嘗試註釋掉了下面兩行都得到了 NameError
的錯誤,我不知道 Zed 這題想幹嘛。
file_again = input("> ")
txt_again = open(file_again)
15.5 那種方法獲得文件名更好?
首先要分情況,根據開發需要選擇。
單說本題,我認爲使用 input
兼容性更好打字更少,比如遇到有文件名有空格的時候。用參數需要爲文件名添加引號,防止程序誤認爲是兩個參數。
但是如果從程序執行速度來說 input
需要人工兩次錄入(執行一次,文件名一次)會增加程序運行時間。
15.6 運行 pydoc file
python3 中使用 pydoc file 已經報錯了,沒有這個東西。原因大致是 Py2 的時候使用的是 C 語言的 I/O 。而 Py3 使用了新的的 I/O 雖然常用的方法沒什麼變化,使用起來也沒什麼問題,但是背後實現的方法已經發生了變化沒有 file 這個類了。
Zed 的本意可能是讓我們學會看文檔,以及預習之後會用到的知識。本題是文件讀取,下一題則是文件讀寫,所有我們不妨先看看我們本題打開的這份文本文件的文檔。
額外內容 —— 查看當前變量的文檔
之前我有提到過一次,除了 pydoc
以外,還可以在命令行中使用 help()
這個方法來查看函數或方法的文檔:
# 打開文件 'ex15_sample.txt' 並賦值個 file
>>> file = open('ex15_sample.txt')
# 使用 help 查看 file 的文檔
>>> help(file)
使用 help
後會看到大致如上的內容(部分截圖),介紹當前查看元素的幫助文檔,我們從第一行可以看到,在 Py3 環境下使用 open
打開的這個東西的幫助文檔,實際上是 TextIOWrapper
對象的幫助文檔。
而用同樣的方法在 Py2 環境下打開一個 txt 文檔看到的確實下面的。
找到了嗎?它其實是一個 file
的對象,這樣難怪我們在 Py3 無法用 pydoc 查看 file
的幫助文檔了。
15.8 關閉文件
如果我們使用的是向文件寫入東西,如果不關閉的話,是無法保存的。因此在完成文件操作之後切記關閉文件:
# 關閉文件
txt.close()
txt_again.close()
不過還有一種自動關閉文件的方法,我估計後面會有。着急的自行搜索 with open