Python:讀寫文件(I/O) | 組織文件
1. I/O 概述
程式與用戶交互涉及到程式的輸入輸出(I/O)
一種類型是字元串,通過input() 和 print() 函數以及數據類型轉換類函數如(int()),實現數據的輸入輸出。
另一種類型是讀寫文件,通過文件的創建、讀和寫,實現數據的輸入輸出。
本文敘述關於讀寫文件與組織文件
2. 文件與文件路徑
2.1 文件及文件類型
2.1.1 文件
文件是一個位的序列,可被應用程式翻譯成文本文件和二進位文件。
位是存儲在電腦中的最小單位,位代表設備的某一狀態,但只能是兩種狀態之一(設備開關斷開或合上)。
文件可分類為文本文件和二進位文件
2.1.2 文本文件
文本文件是字元文件,只含有ASCII或Unicode字元,要存儲整數、浮點數或其他數據結構,必須要將它們轉化成對應的字元格式。
2.1.3 二進位文件
二進位文件是其他所有文件。諸如字處理文檔、 PDF、 影像、 電子表格和可執行程式。
2.2 文件路徑
文件以文件夾 (folder)的形式組織起來。文件夾也叫目錄(directory)。
每個正在運行的程式都有一個 『『當前目錄」作為大多數操作的默認目錄。例如,當你打開一個文件來讀取時,Python 會在當前目錄下尋找這個文件。
指明一個文件或者目錄的字元串,叫做路徑 (path),比如:‘/Python36/scripts’
os 模組提供了操作文件和目錄的函數。
2.2.1 相對路徑
一個簡單的文件名,如 memo.txt ,同樣被看做是一個路徑,只不過是相對路徑 ,因為它是相對於當前目錄而言的。相對路徑(relative path)就是從當前目錄開始的路徑。
下面程式碼揭示了 os.path.exists() 的實際
>>> import os >>> os.getcwd() # getcwd() 返回當前工作目錄 'D:\\Python36' >>> os.chdir('C:\\Windows\\System32') # chdir() 切換當前目錄 >>> os.getcwd() 'C:\\Windows\\System32'
>>> import os >>> os. path . exists ('(讀寫文件)瘋狂填詞2.txtt ') # 這個文件在電腦上存在,但不存在當前目錄 False >>> os.path.exists('正則程式碼實踐strip.py') # 這個文件存在當前目錄 True
2.2.2 絕對路徑
一個以 / 開頭的路徑和當前目錄無關,叫做絕對路徑 。絕對路徑 (absolute path)就是從文件系統頂部開始的路徑。
下面程式碼揭示了 os.path.abspath() 的實際效果以及 os.path.relpath() 的用法
>>> import os >>> os.path.abspath('正則程式碼實踐strip.py') 'D:\\Python36\\正則程式碼實踐strip.py'
>>> import os >>> os.path.abspath('正則程式碼實踐strip.py') 'D:\\Python36\\正則程式碼實踐strip.py' >>> os.path.abspath('(讀寫文件)瘋狂填詞2.py') # 這個文件是當前目錄沒有的 'D:\\Python36\\(讀寫文件)瘋狂填詞2.py' >>> os.path.abspath(r'\Python編程快速上手++讓繁瑣工作自\(讀寫文件)瘋狂填詞2.py') # 這個目錄也是當前目錄不存在的 'D:\\Python編程快速上手++讓繁瑣工作自\\(讀寫文件)瘋狂填詞2.py' >>> os.path.abspath(r'\Desktop\Python編程快速上手++讓繁瑣工作自動化\(讀寫文件)瘋狂填詞2.py') 'D:\\Desktop\\Python編程快速上手++讓繁瑣工作自動化\\(讀寫文件)瘋狂填詞2.py' >>> os.path.abspath(r'\Administrator\Desktop\Python編程快速上手++讓繁瑣工作自動化\(讀寫文件)瘋狂填詞2.py') 'D:\\Administrator\\Desktop\\Python編程快速上手++讓繁瑣工作自動化\\(讀寫文件)瘋狂填詞2.py' # 如果沒有指明最頂部根目錄,則該函數返回的目錄的頂部都是當前目錄的頂部,即"D:\\" >>> os.path.abspath(r'C:\Users\Administrator\Desktop\Python編程快速上手++讓繁瑣工作自動化\(讀寫文件)瘋狂填詞2.py') 'C:\\Users\\Administrator\\Desktop\\Python編程快速上手++讓繁瑣工作自動化\\(讀寫文件)瘋狂填詞2.py'
>>> import os >>> os.path.relpath('C:\\Windows', 'C:\\') 'Windows' >>> os.path.relpath('C:\\Windows', 'C:\\spam\\eggs') '..\\..\\Windows' >>> os.getcwd() 'D:\\Python36'
2.2.3 用 os.makedirs() 創建新文件夾(目錄)
os.makedirs()將創建所有必要的中間文件夾,目的是確保完整路徑名存在。
>>> import os >>> os.makedirs('D:\\abc\\def\\g') >>> os.chdir(('D:\\abc\\def\\g')
2.2.4 用 os.path.join() 構建所有作業系統上都有效的路徑
這個方法很有用,例如構建文件路徑(創建文件的同時創建路徑)
>>> import os >>> os.path.join('D:\\Python36', 'test.txt') 'D:\\Python36\\test.txt'
3. 讀寫文件
3.1 用 open() 函數創建或打開文件
open() 函數返回一個 File 類型對象,將該對象保存於變數中,就可以調用 File 對象的方法
>>> file = open('hello.txt')
如果當前目錄下沒有 ‘hello.txt’ 文件,則創建該文件並打開。
3.2 用 read() 或 readlines()方法讀取文件
open() 函數默認以「讀」模式打開文件,因此不能進行寫入操作,但可以用 read() 方法讀取文件內容(但要實現下面程式碼結果,先要手動打開文件,並敲入對應的內容),
read() 方法就返回保存在該文件中的字元串。
readlines() 方法,從文件取得一個字元串的列表。列表中的每個字元串就是文本中的每一行。
>>> helloContent = file.read() >>> helloContent 'Hello world!'
>>> sonnetFile = open('sonnet29.txt') >>> sonnetFile.readlines() [When, in disgrace with fortune and men's eyes,\n', ' I all alone beweep my outcast state,\n', And trouble deaf heaven with my bootless cries,\n', And look upon myself and curse my fate,']
3.3 用 write()方法寫入文件
將‘w’作為第二個參數傳遞給 open(),將以寫模式打開該文件,便可以調用 write() 方法將內容寫入文件。
’w’ 模式將會刪除文件原有內容,重新寫入。
如果不希望刪除原有內容,可以用 ‘a’ 模式將內容以添加的方式寫入文件。
還有二進位寫入模式 ‘wb’ 等,更多模式請參考Python文檔。
>>> baconFile = open('bacon.txt', 'w') >>> baconFile.write('Hello world!\n') 13 >>> baconFile.close() >>> baconFile = open('bacon.txt', 'a') >>> baconFile.write('Bacon is not a vegetable.') 25 >>> baconFile.close() >>> baconFile = open('bacon.txt') >>> content = baconFile.read() >>> baconFile.close() >>> print(content) Hello world! Bacon is not a vegetable.
write() 返回值是被寫入字元的個數。文件對象將跟蹤自身的位置,所以下次你調用 write的時候,它會在文件末尾添加新的數據。
3.4 修改文件
調用 readlines() 方法,利用正則表達匹配修改內容或調用字元串相關方法修改內容,重新寫入新文件。備份原文件,刪除原文件。
3.5 用 colse() 方法關閉文件
如果用上下文管理器(with語句)則不需要調用colse()方法,否則應該在最後調用colse()方法。
>>> baconFile = open('bacon.txt', 'w') >>> baconFile.write('Hello world!\n') 13 >>> baconFile.close()
4. 組織文件
參考自《Python編程快速上手 讓繁瑣工作自動化》
4.1 查看目錄下所有文件
調用 os.listdir(path) 將返回傳入函數路徑(path)下所有文件名字元串的列表,包含 path 中的每個文件
>>> os.listdir('C:\\Windows\\System32') ['0409', '12520437.cpx', '12520850.cpx', '5U877.ax', 'aaclient.dll', ...... 'xwtpdui.dll', 'xwtpw32.dll', 'zh-CN', 'zh-HK', 'zh-TW', 'zipfldr.dll']
4.2 遍歷目錄樹
os.walk()在循環的每次迭代中,返回 3 個值:
1. 當前文件夾名稱的字元串。
2. 當前文件夾中子文件夾的字元串的列表。
3. 當前文件夾中文件的字元串的列表。
import os for folderName, subfolders, filenames in os.walk('C:\\delicious'): print('當前目錄(文件夾) folder 是 ' + folderName) for subfolder in subfolders: print('目錄下子文件夾 subflder 是 ' + folderName + ': ' + subfolder) for filename in filenames: print('目錄下文件 file 是 ' + folderName + ': '+ filename) print('')
輸出如下,意思就是os.walk(),先搜索文件夾(根目錄)下的所有子文件夾和文件,而對根目錄下的每個子文件夾又做了同樣的事情,層次迭代,結果就是找到了所有的文件夾與文件(即遍歷了目錄樹)
當前目錄文件夾 folder 是 C:\delicious
目錄下子文件夾 subflder 是 C:\delicious: cats
目錄下子文件夾 subflder 是 C:\delicious: walnut
目錄下文件 file 是 C:\delicious: spam.txt
當前目錄文件夾 folder 是 C:\delicious\cats
目錄下文件 file 是 C:\delicious\cats: catnames.txt
目錄下文件 file 是 C:\delicious\cats: zophie.jpg
當前目錄文件夾 folder 是 C:\delicious\walnut
目錄下子文件夾 subflder 是 C:\delicious\walnut: waffles
當前目錄文件夾 folder 是 C:\delicious\walnut\waffles
目錄下文件 file 是 C:\delicious\walnut\waffles: butter.txt.
4.3 shutil 模組
4.3.1 複製文件和文件夾
調用 shutil.copy()
>>> import shutil, os >>> os.chdir('C:\\') >>> shutil.copy('C:\\spam.txt', 'C:\\delicious') 'C:\\delicious\\spam.txt' >>> shutil.copy('eggs.txt', 'C:\\delicious\\eggs2.txt') 'C:\\delicious\\eggs2.txt'
4.3.2 文件和文件夾的移動與改名
調用 shutil.move(source, destination), 下面程式碼:
1、如果文件夾 C:\eggs 中原來存在一個文件 bacon.txt,它會被C:\\bacon.txt 覆蓋(替換)。
2、目標文件夾 C:\\eggs 必須存在
3、 shutil.move() 方法可以實現改文件名
>>> import shutil >>> shutil.move('C:\\bacon.txt', 'C:\\eggs') 'C:\\eggs\\bacon.txt' >>> shutil.move('C:\\bacon.txt', 'C:\\eggs\\new_bacon.txt') 'C:\\eggs\\new_bacon.txt'
4.3.3永久刪除文件和文件夾
利用 os 模組中的函數,可以刪除一個文件或一個空文件夾。但利用 shutil 模組,可以刪除一個文件夾及其所有的內容。
• 調用 os.unlink(path)將刪除 path 處的文件。
• 調用 os.rmdir(path)將刪除 path 處的文件夾。該文件夾必須為空,其中沒有任何文件和文件夾。
• 調用 shutil.rmtree(path)將刪除 path 處的文件夾,它包含的所有文件和文件夾都會被刪除。
以上函數都是永久刪除用時要特別小心
import os for filename in os.listdir(): if filename.endswith('.rxt'): #os.unlink(filename) print(filename)
4.3.4 用 send2trash 模組安全地刪除
send2trash() 函數只能將文件送到垃圾箱, 不能從中恢復文件。
>>> import send2trash >>> baconFile = open('bacon.txt', 'a') # creates the file >>> baconFile.write('Bacon is not a vegetable.') 25 >>> baconFile.close() >>> send2trash.send2trash('bacon.txt')
4.4.zipfile 模組
4.4.1 讀取 ZIP 文件
>>> import zipfile, os >>> os.chdir('C:\\') # move to the folder with example.zip >>> exampleZip = zipfile.ZipFile('example.zip') >>> exampleZip.namelist() ['spam.txt', 'cats/', 'cats/catnames.txt', 'cats/zophie.jpg'] >>> spamInfo = exampleZip.getinfo('spam.txt') >>> spamInfo.file_size 13908 >>> spamInfo.compress_size 3828 >>> 'Compressed file is %sx smaller!' % (round(spamInfo.file_size / spamInfo.compress_size, 2)) 'Compressed file is 3.63x smaller!' >>> exampleZip.close()
4.4.2 解壓文件
運行這段程式碼後, example.zip 的內容將被解壓縮到 C:\。
或者, 你可以向extractall()傳遞的一個文件夾名稱,它將文件解壓縮到那個文件夾, 而不是當前工作目錄。
>>> import zipfile, os >>> os.chdir('C:\\') # move to the folder with example.zip >>> exampleZip = zipfile.ZipFile('example.zip') >>> exampleZip.extractall() >>> exampleZip.close()
4.4.3 創建和添加到 ZIP 文件
下面程式碼 zipfile.ZipFile()方法中第二個參數 zipfile.ZIP_DEFLATED 是指定了 deflate 壓縮演算法,它對各種類型的數據都很有效
這段程式碼將創建一個新的 ZIP 文件, 名為 new.zip, 它包含 spam.txt 壓縮後的內容。
和寫入文件同樣,寫模式將擦除 ZIP 文件中所有原有的內容。如果只是希望將文件添加到原有的 ZIP 文件中, 就要向 zipfile.ZipFile()傳入‘a’作為第二個參數,以添加模式打開 ZIP 文件
>>> import zipfile >>> newZip = zipfile.ZipFile('new.zip', 'w') >>> newZip.write('spam.txt', compress_type=zipfile.ZIP_DEFLATED) >>> newZip.close()