withopen('pi_digits.txt') as file_object:contents = file_object.read()print(contents.rstrip())
由于文件夾 text_files 位于文件夾 python_work 中,因此可使用相對文件路 徑來打開該文件夾中的文件。相對文件路徑讓 Python 到指定的位置去查找,而該位置是相對于當前運行的程 序所在目錄的。在 Linux 和 OS X 中,你可以這樣編寫代碼:
withopen('text_files/filename.txt') as file_object:
這行代碼讓 Python 到文件夾 python_work 下的文件夾 text_files 中去查找指定的 .txt 文件。在 Windows 系統(tǒng)中,在文件路徑中使用反斜杠( \ )而不是斜杠( / ):with open('text_files\filename.txt') as file_object: 你還可以將文件在計算機中的準確位置告訴 Python ,這樣就不用關心當前運行的程序存儲在什么地方了。這稱為絕對文件路徑 。在相對路徑行不通時,可使用絕對路徑。例如, 如果 text_files 并不在文件夾 python_work 中,而在文件夾 other_files 中,則向 open() 傳遞路徑 ‘text_files/ filename.txt’ 行不通,因為 Python 只在文件夾 python_work 中查找 該位置。為明確地指出你希望 Python 到哪里去查找,你需要提供完整的路徑。 絕對路徑通常比相對路徑更長,因此將其存儲在一個變量中,再將該變量傳遞給 open() 會有所幫助。在 Linux 和 OS X 中,絕對路徑類似于下面這樣:
file_path = '/home/ehmatthes/other_files/text_files/filename.txt' with open(file_path) as file_object: 而在 Windows 系統(tǒng)中,它們類似于下面這樣:
file_path = 'C:\Users\ehmatthes\other_files\text_files\filename.txt'
with open(file_path) as file_object:
通過使用絕對路徑,可讀取系統(tǒng)任何地方的文件。就目前而言,最簡單的做法是,要么將數(shù)據(jù)文件存儲在程序文件所在的目錄,要么將其存儲在程序文件所在目錄下的一個文件 夾(如 text_files )中。 注意 Windows 系統(tǒng)有時能夠正確地解讀文件路徑中的斜杠。如果你使用的是 Windows 系統(tǒng),且結果不符合預期,請確保在文件路徑中使用的是反斜杠。
10.1.3 逐行讀取
讀取文件時,常常需要檢查其中的每一行:你可能要在文件中查找特定的信息,或者要以某種方式修改文件中的文本。例如,你可能要遍歷一個包含天氣數(shù)據(jù)的文件,并使用天
氣描述中包含字樣 sunny 的行。在新聞報道中,你可能會查找包含標簽 <headline> 的行,并按特定的格式設置它。
要以每次一行的方式檢查文件,可對文件對象使用 for 循環(huán):
file_reader.py
? filename = 'pi_digits.txt'
?
? withopen(filename) as file_object:
forlinein file_object:
print(line)
在?處,我們將要讀取的文件的名稱存儲在變量 filename 中,這是使用文件時一種常見的做法。由于變量 filename 表示的并非實際文件 —— 它只是一個讓 Python 知道到哪里
去查找文件的字符串,因此可輕松地將 'pi_digits.txt' 替換為你要使用的另一個文件的名稱。調用 open() 后,將一個表示文件及其內容的對象存儲到了變
量 file_object 中(見?)。這里也使用了關鍵字 with ,讓 Python 負責妥善地打開和關閉文件。為查看文件的內容,我們通過對文件對象執(zhí)行循環(huán)來遍歷文件中的每一行(見
?)。
我們打印每一行時,發(fā)現(xiàn)空白行更多了:
3.141592653589793238462643383279
為何會出現(xiàn)這些空白行呢?因為在這個文件中,每行的末尾都有一個看不見的換行符,而 print 語句也會加上一個換行符,因此每行末尾都有兩個換行符:一個來自文件,另一
個來自 print 語句。要消除這些多余的空白行,可在 print 語句中使用 rstrip() :
filename = 'pi_digits.txt'withopen(filename) as file_object:
forlinein file_object:
print(line.rstrip())
現(xiàn)在,輸出又與文件內容完全相同了:
3.14159265358979323846264338327910.1.4 創(chuàng)建一個包含文件各行內容的列表
使用關鍵字 with 時, open() 返回的文件對象只在 with 代碼塊內可用。如果要在 with 代碼塊外訪問文件的內容,可在 with 代碼塊內將文件的各行存儲在一個列表中,并
在 with 代碼塊外使用該列表:你可以立即處理文件的各個部分,也可推遲到程序后面再處理。
下面的示例在 with 代碼塊中將文件 pi_digits.txt 的各行存儲在一個列表中,再在 with 代碼塊外打印它們:
filename = 'pi_digits.txt'
?
?
withopen(filename) as file_object:
lines = file_object.readlines()
forlineinlines:
print(line.rstrip())
?處的方法 readlines() 從文件中讀取每一行,并將其存儲在一個列表中;接下來,該列表被存儲到變量 lines 中;在 with 代碼塊外,我們依然可以使用這個變量。在?
處,我們使用一個簡單的 for 循環(huán)來打印 lines 中的各行。由于列表 lines 的每個元素都對應于文件中的一行,因此輸出與文件內容完全一致。
10.1.5 使用文件的內容
將文件讀取到內存中后,就可以以任何方式使用這些數(shù)據(jù)了。下面以簡單的方式使用圓周率的值。首先,我們將創(chuàng)建一個字符串,它包含文件中存儲的所有數(shù)字,且沒有任何空
格:
pi_string.py
filename = 'pi_digits.txt'withopen(filename) as file_object:
lines = file_object.readlines()
?
?
pi_string = ''forlineinlines:pi_string += line.rstrip()
?
print(pi_string)
print(len(pi_string))
就像前一個示例一樣,我們首先打開文件,并將其中的所有行都存儲在一個列表中。在?處,我們創(chuàng)建了一個變量 —— pi_string ,用于存儲圓周率的值。接下來,我們使用
一個循環(huán)將各行都加入 pi_string ,并刪除每行末尾的換行符(見?)。在?處,我們打印這個字符串及其長度:
3.14159265358979323846264338327936
在變量 pi_string 存儲的字符串中,包含原來位于每行左邊的空格,為刪除這些空格,可使用 strip() 而不是 rstrip() :
filename = 'pi_30_digits.txt'withopen(filename) as file_object:
lines = file_object.readlines()
pi_string = ''forlineinlines:
pi_string += line.strip()
print(pi_string)
print(len(pi_string))
這樣,我們就獲得了一個這樣的字符串:它包含精確到 30 位小數(shù)的圓周率值。這個字符串長 32 字符,因為它還包含整數(shù)部分的 3 和小數(shù)點:
3.14159265358979323846264338327932
注意 讀取文本文件時, Python 將其中的所有文本都解讀為字符串。如果你讀取的是數(shù)字,并要將其作為數(shù)值使用,就必須使用函數(shù) int() 將其轉換為整數(shù),或使用
函數(shù) float() 將其轉換為浮點數(shù)。
10.1.6 包含一百萬位的大型文件
前面我們分析的都是一個只有三行的文本文件,但這些代碼示例也可處理大得多的文件。如果我們有一個文本文件,其中包含精確到小數(shù)點后 1000000 位而不是 30 位的圓周率
值,也可創(chuàng)建一個包含所有這些數(shù)字的字符串。為此,我們無需對前面的程序做任何修改,只需將這個文件傳遞給它即可。在這里,我們只打印到小數(shù)點后 50 位,以免終端為顯
示全部 1000000 位而不斷地翻滾:
pi_string.py
filename = 'pi_million_digits.txt'withopen(filename) as file_object:
lines = file_object.readlines()
pi_string = ''forlineinlines:
pi_string += line.strip()
print(pi_string[:52] + "...")
print(len(pi_string))
輸出表明,我們創(chuàng)建的字符串確實包含精確到小數(shù)點后 1000000 位的圓周率值:
3.14159265358979323846264338327950288419716939937510...
1000002
對于你可處理的數(shù)據(jù)量, Python 沒有任何限制;只要系統(tǒng)的內存足夠多,你想處理多少數(shù)據(jù)都可以。
注意 要運行這個程序(以及后面的眾多示例),你需要從 https://www.nostarch.com/pythoncra-shcourse/ 下載相關的資源。
10.1.7 圓周率值中包含你的生日嗎
我一直想知道自己的生日是否包含在圓周率值中。下面來擴展剛才編寫的程序,以確定某個人的生日是否包含在圓周率值的前 1000000 位中。為此,可將生日表示為一個由數(shù)字
組成的字符串,再檢查這個字符串是否包含在 pi_string 中:
filename = 'pi_million_digits.txt'withopen(filename) as file_object:
lines = file_object.readlines()
pi_string = ''forlineinlines:
pi_string += line.rstrip()
?
?
birthday = input("Enter your birthday, in the form mmddyy: ")
if birthday in pi_string:
print("Your birthday appears in the first million digits of pi!")
else:
print("Your birthday does not appear in the first million digits of pi.")
在?處,我們提示用戶輸入其生日,在接下來的?處,我們檢查這個字符串是否包含在 pi_string 中。運行一下這個程序:Enter your birthdate, inthe form mmddyy: 120372
Your birthday appears inthefirst million digits ofpi!
我的生日確實出現(xiàn)在了圓周率值中!讀取文件的內容后,就可以以你能想到的任何方式對其進行分析。
動手試一試
10-1 Python 學習筆記 :在文本編輯器中新建一個文件,寫幾句話來總結一下你至此學到的 Python 知識,其中每一行都以 “In Python you can” 打頭。將這個文件命名為
learning_python.txt ,并將其存儲到為完成本章練習而編寫的程序所在的目錄中。編寫一個程序,它讀取這個文件,并將你所寫的內容打印三次:第一次打印時讀取整個
文件;第二次打印時遍歷文件對象;第三次打印時將各行存儲在一個列表中,再在 with 代碼塊外打印它們。
10-2 C 語言學習筆記 :可使用方法 replace() 將字符串中的特定單詞都替換為另一個單詞。下面是一個簡單的示例,演示了如何將句子中的 'dog' 替換為 'cat'
:
>>> message = "I really like dogs."
>>> message.replace('dog', 'cat')
'I really like cats.'
讀取你剛創(chuàng)建的文件 learning_python.txt 中的每一行,將其中的 Python 都替換為另一門語言的名稱,如 C 。將修改后的各行都打印到屏幕上。
10.2 寫入文件
保存數(shù)據(jù)的最簡單的方式之一是將其寫入到文件中。通過將輸出寫入文件,即便關閉包含程序輸出的終端窗口,這些輸出也依然存在:你可以在程序結束運行后查看這些輸出,
可與別人分享輸出文件,還可編寫程序來將這些輸出讀取到內存中并進行處理。
10.2.1 寫入空文件
要將文本寫入文件,你在調用 open() 時需要提供另一個實參,告訴 Python 你要寫入打開的文件。為明白其中的工作原理,我們來將一條簡單的消息存儲到文件中,而不是將其打
印到屏幕上:
write_message.py
filename = 'programming.txt'
?
?
withopen(filename, 'w') as file_object:
file_object.write("I love programming.")
在這個示例中,調用 open() 時提供了兩個實參(見?)。第一個實參也是要打開的文件的名稱;第二個實參( 'w' )告訴 Python ,我們要以寫入模式 打開這個文件。打開文件
時,可指定讀取模式 ( 'r' )、寫入模式 ( 'w' )、附加模式 ( 'a' )或讓你能夠讀取和寫入文件的模式( 'r+' )。如果你省略了模式實參, Python 將以默認的只讀模式打
開文件。
如果你要寫入的文件不存在,函數(shù) open() 將自動創(chuàng)建它。然而,以寫入( 'w' )模式打開文件時千萬要小心,因為如果指定的文件已經(jīng)存在, Python 將在返回文件對象前清空
該文件。
在?處,我們使用文件對象的方法 write() 將一個字符串寫入文件。這個程序沒有終端輸出,但如果你打開文件 programming.txt ,將看到其中包含如下一行內容:
programming.txt
I love programming.
相比于你的計算機中的其他文件,這個文件沒有什么不同。你可以打開它、在其中輸入新文本、復制其內容、將內容粘貼到其中等。
注意 Python 只能將字符串寫入文本文件。要將數(shù)值數(shù)據(jù)存儲到文本文件中,必須先使用函數(shù) str() 將其轉換為字符串格式。
10.2.2 寫入多行
函數(shù) write() 不會在你寫入的文本末尾添加換行符,因此如果你寫入多行時沒有指定換行符,文件看起來可能不是你希望的那樣:
filename = 'programming.txt'withopen(filename, 'w') as file_object:
file_object.write("I love programming.")
file_object.write("I love creating new games.")
如果你打開 programming.txt ,將發(fā)現(xiàn)兩行內容擠在一起:
I love programming.I love creating new games.
要讓每個字符串都單獨占一行,需要在 write() 語句中包含換行符:
filename = 'programming.txt'withopen(filename, 'w') as file_object:
file_object.write("I love programming.\n")
file_object.write("I love creating new games.\n")
現(xiàn)在,輸出出現(xiàn)在不同行中:I love programming.
I love creating new games.
像顯示到終端的輸出一樣,還可以使用空格、制表符和空行來設置這些輸出的格式。
10.2.3 附加到文件
如果你要給文件添加內容,而不是覆蓋原有的內容,可以附加模式 打開文件。你以附加模式打開文件時, Python 不會在返回文件對象前清空文件,而你寫入到文件的行都將添加
到文件末尾。如果指定的文件不存在, Python 將為你創(chuàng)建一個空文件。
下面來修改 write_message.py ,在既有文件 programming.txt 中再添加一些你酷愛編程的原因:
write_message.py
filename = 'programming.txt'
?
?
withopen(filename, 'a') as file_object:
file_object.write("I also love finding meaning in large datasets.\n")
file_object.write("I love creating apps that can run in a browser.\n")
在?處,我們打開文件時指定了實參 'a' ,以便將內容附加到文件末尾,而不是覆蓋文件原來的內容。在?處,我們又寫入了兩行,它們被添加到文件 programming.txt 末尾:
programming.txt
I
I
I
I
love
love
also
love
programming.
creating new games.
love finding meaning in large datasets.
creating apps that can run ina browser.
最終的結果是,文件原來的內容還在,它們后面是我們剛添加的內容。
動手試一試
10-3 訪客 :編寫一個程序,提示用戶輸入其名字;用戶作出響應后,將其名字寫入到文件 guest.txt 中。
10-4 訪客名單 :編寫一個 while 循環(huán),提示用戶輸入其名字。用戶輸入其名字后,在屏幕上打印一句問候語,并將一條訪問記錄添加到文件 guest_book.txt 中。確保這
個文件中的每條記錄都獨占一行。
10-5 關于編程的調查 :編寫一個 while 循環(huán),詢問用戶為何喜歡編程。每當用戶輸入一個原因后,都將其添加到一個存儲所有原因的文件中。