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()