1. 程式人生 > >python讀取檔案小結

python讀取檔案小結

你想通過python從檔案中讀取文字或資料。

一.最方便的方法是一次性讀取檔案中的所有內容並放置到一個大字串中:

  1. all_the_text = open('thefile.txt').read( )     # 文字檔案中的所有文字  

  2. all_the_data = open('abinfile','rb').read( )    # 二進位制檔案中的所有資料 

為了安全起見,最好還是給開啟的檔案物件指定一個名字,這樣在完成操作之後可以迅速關閉檔案,防止一些無用的檔案物件佔用記憶體。舉個例子,對文字檔案讀取:

  1. file_object = open('thefile.txt')  

  2. try:  

  3.      all_the_text = file_object.read( )  

  4. finally:  

  5.      file_object.close( ) 

不一定要在這裡用Try/finally語句,但是用了效果更好,因為它可以保證檔案物件被關閉,即使在讀取中發生了嚴重錯誤。

二.最簡單、最快,也最具Python風格的方法是逐行讀取文字檔案內容,並將讀取的資料放置到一個字串列表中:

  1. list_of_all_the_lines = file_object.readlines( ) 

這樣讀出的每行文字末尾都帶有"\n"符號;如果你不想這樣,還有另一個替代的辦法,比如:

  1. list_of_all_the_lines = file_object.read( ).splitlines( )  

  2. list_of_all_the_lines = file_object.read( ).split('\n')  

  3. list_of_all_the_lines = [L.rstrip('\n') for L in file_object] 

最簡單最快的逐行處理文字檔案的方法是,用一個簡單的for迴圈語句:

  1. for line in file_object:  

  2.       process line 

這種方法同樣會在每行末尾留下"\n"符號;可以在for迴圈的主體部分加一句:

  1. lineline = line.rstrip('\n') 

或者,你想去除每行的末尾的空白符(不只是'\n'\),常見的辦法是:

  1. lineline = line.rstrip( ) 

三.討論

除非要讀取的檔案非常巨大,不然一次性讀出所有內容放進記憶體並進一步處理是最快和最方便的辦法。內建函式open建立了一個Python的檔案物件(另外,也可以通過呼叫內建型別file建立檔案物件)。你對該物件呼叫read方法將讀出所有內容(無論是文字還是二進位制資料),並放入一個大字串中。如果內容是文字,可以選擇用split方法或者更專用的splitlines將其切分成一個行列表。由於切分字串到單行是很常見的需求,還可以直接對檔案物件呼叫readlines,進行更方便更快速的處理。

可以直接對檔案物件應用迴圈語句,或者將它傳遞給一個需要可迭代物件的處理者,比如list或者max。當它被當做一個可迭代物件處理時,一個被開啟並被讀取的檔案物件中的每一個文字行都變成了迭代子項(因此,這也只適用於文字檔案)。這種逐行迭代的處理方式很節省記憶體資源,速度也不錯。

在UNIX或者類UNIX系統中,比如Linux,Mac OS X,或者其他BSD變種,文字檔案和二進位制檔案其實並沒有什麼區別。在Windows和老的Macintosh系統中,換行符不是標準的 '\n',而分別是 '\r\n' 和 '\r'。Python會幫助你把這些換行符轉化成 '\n'。這意味著當你開啟二進位制檔案時,需要明確告訴Python,這樣它就不會做任何轉化。為了達到這個目的,必須傳遞 'rb' 給open的第二個引數。在類UNLX平臺上,這麼做也不會有什麼壞處,而且總是區分文字檔案和二進位制檔案是一個好習慣,當然在那些平臺上這並不是強制性的要求。不過這些好習慣會讓你的程式具有更好的可讀性,也更易於理解,同時還能具有更好的平臺相容性。

如果不確定某文字檔案會用什麼樣的換行符,可以將open的第二個引數設定為 'rU',指定通用換行符轉化。這讓你可以自由地在Windows、UNIX(包括Mac OS X),以及其他的老Macintosh平臺上交換檔案,完全不用擔心任何問題:無論你的程式碼在什麼平臺上執行,各種換行符都被對映成 '\n'。

可以對open函式產生的檔案物件直接呼叫read方法,如解決方案中給出的第一個程式碼片段所示。當你這麼做的時候,你在完成讀取的同時,也失去了對那個檔案物件的引用。在實踐中,Python注意到了這種當場即時失去引用的情況,它會迅速關閉該檔案。然而,更好的辦法仍然是給open產生的結果指定一個名字,這樣當你完成了處理,可以顯式地自行關閉該檔案。這能夠確保該檔案處於被開啟狀態的時間儘量的短,即使是在Jython,IronPython或其他變種Python平臺上(這些平臺的高階垃圾回收機制可能會推遲自動回收,不像現在的基於C的Python平臺,CPython會立刻執行回收)。為了確保檔案物件即使在處理過程發生錯誤的情況下仍能夠正確關閉,應該使用try/finally語句,這是一種穩健而嚴謹的處理方式。

  1. file_object = open('thefile.txt')  

  2. try:  

  3.       for line in file_object:  

  4.              process line  

  5. finally:  

  6.       file_object.close( ) 

注意,不要把對open的呼叫放入到try/finally語句的try子句中(這是初學者很常見的錯誤)。如果在開啟檔案的時候就發生了錯誤,那就沒有什麼東西需要關閉,而且,也沒有什麼實質性的東西繫結到了file_object這個名字上,當然也就不應該呼叫file_object.close()。

如果選擇一次讀取檔案的一小部分,而不是全部,方式就有點不同了。下面給出一個例子,一次讀取一個二進位制檔案的100個位元組,一直讀到檔案末尾:

  1. file_object = open('abinfile', 'rb')  

  2. try:  

  3.       while True:  

  4.             chunk = file_object.read(100)  

  5.             if not chunk:  

  6.                   break  

  7.             do_something_with(chunk)  

  8. finally:  

  9.       file_object.close( ) 

給read方法傳入一個引數N,確保了read方法只讀取下N個位元組(或更少,如果讀取位置已經很接近檔案末尾的話)。當抵達檔案末尾時,read返回空字串。複雜的迴圈最好被封裝成可複用的生成器(generator)。對於這個例子,我們只能將其邏輯的一部分進行封裝,這是因為生成器(generator)的yield關鍵字不被允許出現在try/finally語句的try子句中。如果要拋棄try/finally語句對檔案關閉的保護,我們可以這麼做:

  1. def read_file_by_chunks(filename, chunksize=100):  

  2.       file_object = open(filename, 'rb')  

  3.       while True:  

  4.             chunk = file_object.read(chunksize)  

  5.             if not chunk:  

  6.                   break  

  7.             yield chunk  

  8.       file_object.close( ) 

一旦read_file_by_chunks生成器完成,以固定長度讀取和處理二進位制檔案的程式碼就可以寫得極其簡單:

  1. for chunk in read_file_by_chunks('abinfile'):  

  2.       do_something_with(chunk) 

逐行讀取文字檔案的任務更為常見。只需對檔案物件應用迴圈語句,如下:

  1. for line in open('thefile.txt', 'rU'):  

  2.       do_something_with(line) 

為了100%確保完成操作之後沒有無用的已開啟的檔案物件存在,可以將上述程式碼修改得更加嚴密穩固:

  1. file_object = open('thefile.txt', 'rU'):  

  2. try:  

  3.       for line in file_object:  

  4.              do_something_with(line)  

  5. finally:  

  6.       file_object.close( )