處理文件是我們每天最常見的任務之一。 Python具有幾個用於執行文件操作的內置模塊,例如讀取文件,移動文件,獲取文件屬性等。本文總結了您需要了解的許多功能,以涵蓋Python中最常見的文件操作和良好做法。
這是您將在本文中看到的模塊/功能圖。 要了解有關每個操作的更多信息,請繼續閱讀。
圖1. 由xiaoxu guo 提供
當您要讀取或寫入文件時,首先要做的就是打開文件。 Python具有打開的內置函數,該函數打開文件並返回文件對象。 文件對象的類型取決於打開文件的模式。 它可以是文本文件對象,原始二進位文件和緩衝的二進位文件。 每個文件對象都有諸如read()和write()之類的方法。
該代碼塊中有問題,您能識別出來嗎? 我們將在後面討論。
file = open(&34;,&34;)file.read()file.write(&34;)
Python文檔列出了所有可能的文件模式。 表中列出了最常見的模式。 一個重要的規則是,任何與w相關的模式都將首先截斷該文件(如果存在),然後創建一個新文件。 如果您不想覆蓋文件,請謹慎使用此模式,並儘可能使用附加模式。
mode meaningr 打開以供閱讀(默認)r+ 為讀取和寫入打開(文件指針位於文件的開頭)w 打開進行寫入(如果存在則截斷文件)w+ 可以同時進行讀寫(截斷文件,如果存在的話)a 開放寫操作(如果存在,追加到文件末尾,並且文件指針位於文件末尾)
上一個代碼塊中的問題是我們只打開了文件,但沒有關閉文件。 在處理文件時始終關閉文件很重要。 擁有打開的文件對象可能會導致不可預測的行為,例如資源洩漏。 有兩種方法可以確保正確關閉文件。
1.使用close()
第一種方法是顯式使用close()。 一個好的做法是將其放入最後,以便我們可以確保在任何情況下都將關閉該文件。 它使代碼更加清晰,但另一方面,開發人員應該承擔責任,不要忘記關閉它。
try: file = open(&34;,&34;) file.write(&34;)exception Exception as e: logging.exception(e)finally: file.close()
2.使用上下文管理器,將open(...)設置為f
第二種方法是使用上下文管理器。 如果您不熟悉上下文管理器,那麼請查閱Dan Bader用Python編寫的上下文管理器和「 with」語句。 與open()一起使用,因為f語句實現__enter__和__exit__方法來打開和關閉文件。 此外,它將try / finally語句封裝在上下文管理器中,這意味著我們將永遠不會忘記關閉文件。
with open(&34;,&34;) as file: file.write(&34;)
這個上下文管理器解決方案是否總是比close()更好? 這取決於您在哪裡使用它。 以下示例實現了將50,000條記錄寫入文件的3種不同方式。 從輸出中可以看到,use_context_manager_2()函數與其他函數相比性能極低。 這是因為with語句在單獨的函數中,它基本上為每個記錄打開和關閉文件。 這種昂貴的I / O操作會極大地影響性能。
def _write_to_file(file, line): with open(file, &34;) as f: f.write(line)def _valid_records(): for i in range(100000): if i % 2 == 0: yield idef use_context_manager_2(file): for line in _valid_records(): _write_to_file(file, str(line))def use_context_manager_1(file): with open(file, &34;) as f: for line in _valid_records(): f.write(str(line))def use_close_method(file): f = open(file, &34;) for line in _valid_records(): f.write(str(line)) f.close() use_close_method(&34;)use_context_manager_1(&34;)use_context_manager_2(&34;)39;use_close_method& Finished &39; in 0.0231 secs39;use_context_manager_2&39;test.txt&39;r&34;&34;test.txt&34;w+&34;hi\n&34;this is a line\n&34;this is another line\n& >>> cat test.txt this is a line34;cities.csv&34;w+&34;city&34;country&34;city&34;Amsterdam&34;country&34;Netherlands&34;city&34;Berlin&34;country&34;Germany&34;city&34;Shanghai&34;country&34;China& >>> cat cities.csv Amsterdam,Netherlands Shanghai,Chinawith open(&34;, &34;) as file: json.dump({&34;: &34;, &34;: &34;}, file) { &34;: &34;, &34;: &34; }
在文件內移動指針
當我們打開文件時,我們得到一個指向特定位置的文件處理程序。 在r和w模式下,處理程序指向文件的開頭。 在一種模式下,處理程序指向文件的末尾。
tell()和seek()
當我們從文件中讀取時,指針將移動到下一個讀取將開始的位置,除非我們告訴指針移動。 您可以使用2種方法來做到這一點:tell()和seek()。
tell()以文件開頭的字節數/字符數的形式返回指針的當前位置。 seek(offset,whence = 0)將處理程序移到一個位置,offset字符距離wherece。 地點可以是:
0:從文件開頭
1:從當前位置開始
2:從文件末尾開始
在文本模式下,wherece僅應為0,偏移應≥0。
with open(&34;, &34;) as f: f.write(&34;) f.seek(9) print(f.tell()) 9abcdef
了解文件狀態
作業系統上的文件系統可以告訴您許多有關文件的實用信息。 例如,文件的大小,創建和修改的時間。 要在Python中獲取此信息,可以使用os或pathlib模塊。 實際上,os和pathlib之間有很多共同之處。 pathlib是比os更面向對象的模塊。
作業系統
獲取完整狀態的一種方法是使用os.stat(「 test.txt」)。 它返回具有許多統計信息的結果對象,例如st_size(文件大小,以字節為單位),st_atime(最新訪問的時間戳),st_mtime(最新修改的時間戳)等。
print(os.stat(&34;))>>> os.stat_result(st_mode=33188, st_ino=8618932538, st_dev=16777220, st_nlink=1, st_uid=501, st_gid=20, st_size=16, st_atime=1597527409, st_mtime=1597527409, st_ctime=1597527409)
您也可以使用os.path單獨獲取統計信息。
os.path.getatime()os.path.getctime()os.path.getmtime()os.path.getsize()
獲取完整狀態的另一種方法是使用pathlib.Path(「 text.txt」)。stat()。 它返回與os.stat()相同的對象。
print(pathlib.Path(&34;).stat())>>> os.stat_result(st_mode=33188, st_ino=8618932538, st_dev=16777220, st_nlink=1, st_uid=501, st_gid=20, st_size=16, st_atime=1597528703, st_mtime=1597528703, st_ctime=1597528703)
在以下各節中,我們將比較os和pathlib的更多方面。
Python有許多內置模塊來處理文件移動。 在您信任Google返回的第一個答案之前,您應該意識到,不同的模塊選擇會導致不同的性能。 一些模塊將阻塞線程,直到文件移動完成,而其他模塊則可能異步執行。
關閉
shutil是用於移動,複製和刪除文件和文件夾的最著名的模塊。 它提供了4種僅複製文件的方法。 copy(),copy2()和copyfile()。
copy()與 copy2():copy2()與copy()非常相似。 不同之處在於copy2()還複製文件的元數據,例如最近的訪問時間,最近的修改時間。 但是根據Python文檔,由於作業系統的限制,即使copy2()也無法複製所有元數據。
shutil.copy(&34;, &34;)shutil.copy2(&34;, &34;)print(pathlib.Path(&34;).stat())print(pathlib.Path(&34;).stat())print(pathlib.Path(&34;).stat()) os.stat_result(st_mode=33152, st_ino=8618884732, st_dev=16777220, st_nlink=1, st_uid=501, st_gid=20, st_size=11, st_atime=1597570395, st_mtime=1597259421, st_ctime=1597570360) os.stat_result(st_mode=33152, st_ino=8618983930, st_dev=16777220, st_nlink=1, st_uid=501, st_gid=20, st_size=11, st_atime=1597570387, st_mtime=1597570395, st_ctime=1597570395) os.stat_result(st_mode=33152, st_ino=8618983989, st_dev=16777220, st_nlink=1, st_uid=501, st_gid=20, st_size=11, st_atime=1597570395, st_mtime=1597259421, st_ctime=1597570395)
367/5000
copy()與 copyfile():copy()將新文件的權限設置為與原始文件相同,但是copyfile()不會複製其權限模式。 其次,copy()的目標可以是目錄。 如果存在同名文件,則將其覆蓋,否則,將創建一個新文件。 但是,copyfile()的目的地必須是目標文件名。
shutil.copy(&34;, &34;)shutil.copyfile(&34;, &34;)print(pathlib.Path(&34;).stat())print(pathlib.Path(&34;).stat())print(pathlib.Path(&34;).stat()) os.stat_result(st_mode=33152, st_ino=8618884732, st_dev=16777220, st_nlink=1, st_uid=501, st_gid=20, st_size=11, st_atime=1597570395, st_mtime=1597259421, st_ctime=1597570360) os.stat_result(st_mode=33152, st_ino=8618983930, st_dev=16777220, st_nlink=1, st_uid=501, st_gid=20, st_size=11, st_atime=1597570387, st_mtime=1597570395, st_ctime=1597570395) permission (st_mode) is changed34;1.csv&34;./source& IsADirectoryError: [Errno 21] Is a directory: &39;
os
os模塊具有一個system()函數,允許您在子shell中執行命令。 您需要將該命令作為參數傳遞給system()。 這與在作業系統上執行的命令具有相同的效果。 為了移動和刪除文件,您還可以在os模塊中使用專用功能。
34;cp 1.csv copy.csv& rename/moveos.system(&34;)os.rename(&34;, &34;)34;rm move.csv&34;1.csv&34;dst_thread.csv&34;dst_multiprocessing.csv&34;cp 1.csv dst_subprocess.csv&34;*.csv&39;1.csv&39;2.csv&34;**/*.csv&39;1.csv&39;2.csv&39;source/3.csv&34;.&34;.csv&34;.&34;.csv&34;1.txt& absoluteprint(os.path.relpath(&34;)) 34;1.txt& absoluteprint(pathlib.Path(&34;)) 34;/home&34;file.txt&34;/home&34;file.txt& relative pathprint(os.path.dirname(&34;))34;source/2.csv& source34;source/2.csv& /Users/<...>/project/sourceprint(os.path.dirname(os.path.abspath(&34;)))# /Users/<...>/project/source
作業系統 路徑庫
最後但並非最不重要的一點是,我想簡要介紹一下os和pathlib。 如Python文檔所述,pathlib是比os更面向對象的解決方案。 它將每個文件路徑表示為適當的對象,而不是字符串。 這給開發人員帶來了很多好處,例如,使連接多個路徑變得更加容易,在不同的作業系統上更加一致,並且可以直接從對象訪問方法。
我希望本文可以提高您處理文件的效率。
原英文連結:https://towardsdatascience.com/knowing-these-you-can-cover-99-of-file-operations-in-python-84725d82c2df