# 檔案系統操作 ###### tags: `python` ## 目錄與檔案路徑 #### 路徑的表達方式 - 相對路徑:指相對於目前目錄的路徑,目前的目錄稱又稱為工作目錄 例如:`example`目錄為目前目錄下有一個子目錄為`example` - 絕對路徑:由系統的根目錄開始表達,Linux和Windows表達方式有其差異 Linux: `/etc/httpd/config` Windows: `C:\Users\Administrator\Documents\File.txt` - `.`:特殊目錄符號,代表目前的目錄 - `..`:特殊目錄符號,代表上一層目錄 #### `os`模組與`os.path`模組 Python內與目錄相關的模組為`os`與`os.path`兩個模組,因為`os.path`為`os`內的子模組,所以只需要`import os`即可。 ##### 取得路徑 ```python= import os print(os.getcwd()) # 取得目前工作目錄 print(os.path.abspath('.')) # 取得目前目錄的絕對路徑 print(os.path.abspath('..')) # 取得目前目錄上一層目錄的絕對路徑 print(os.path.abspath('hello.txt')) # 取得目前目錄下指定檔案的絕對路徑 print(os.path.relpath('D:\\')) # 回傳目前目錄到D:\的相對路徑 print(os.path.relpath('D:\\Downloads')) # 回傳目前目錄到D:\Downloads的相對路徑 print(os.path.relpath('D:\\Downloads', 'hello.txt')) # 回傳目前目錄下hello.txt檔案到D:\Downloads的相對路徑 ``` > **備註:** > > 請記得在字串內,「\」字元需要使用轉譯符號,否則會被當成轉譯字元。 ##### 檢查路徑 ```python= import os print(os.path.exist('hello.txt')) # 檢查目前目錄下是否存在hello.txt檔案 print(os.path.isabs('D:\\Documents\\hello.txt')) # 檢查路徑是否為一個絕對路徑 print(os.path.isdir('repo')) # 檢查路徑是否為目錄 print(os.path.isfile('repo')) # 檢查路徑是否為檔案 ``` 說明: 路徑檢查相關函式回傳直皆為:`True`=存在、`False`=不存在 #### 檔案與目錄操作 ```python= import os os.path.mkdir('sub') # 在目前的目錄下建立sub目錄 os.path.rmdir('sub') # 刪除目前目錄下的sub目錄 os.path.remove('file.txt') # 刪除目前目錄下的file.txt檔案 os.path.chdir('sub') # 將目前的工作目錄切換到sub目錄下 ``` > **補充:** > > 建議在進行目錄操作前,先呼叫`os.path.exists()`檢查是否存在,否則可能會因為建立一個已經存在的目錄而產生例外結束程式。 #### 目錄與檔案的屬性與內容 ``` import os os.path.getsize('hello.txt') # 取得hello.txt檔案大小(單位為bytes) os.listdir() # 列出目前目錄下的內容 os.listdir('D:\\Downloads') # 列出D:\Download目錄下的內容 ``` #### 目錄與檔案的屬性與內容(使用glob模組) 這個模組與os模組最大的差別是可以使用萬用字元「*」與「?」 ```python= import glob print(glob.glob('D:\\Download\\*.txt')) # 列出D:\Downloads目錄下所有附檔名為txt的檔案 print(glob.glob('D:\\Download\\?.txt')) # 列出D:\Downloads目錄下所有附檔名為txt,且主檔名只有一個字元的檔案 ``` #### 列出目錄以及目錄下所有子目錄內容 ``` import os for dir_name, sub_dir_names, filenames in os.walk(): print(dir_name) # 目前工作目錄名稱 print(sub_dir_names) # 目前目錄下所有子目錄名稱 print(file_names) # 目前目錄下所有檔案名稱 ``` ## 讀寫檔案 #### 開啟檔案 所有檔案操作都必須先透過`open()`函式開啟檔案並取得檔案物件後才能進行檔案操作。 檔案開啟模式: | 模式 | 描述 | | :--- | :----------------------------------------------------------- | | t | 文字模式 (預設)。 | | x | 寫模式,新建一個檔案,如果該檔案已存在則會報錯。 | | b | 二進位制模式。 | | + | 開啟一個檔案進行更新(可讀可寫)。 | | r | 以只讀方式開啟檔案。檔案的指標將會放在檔案的開頭。這是預設模式。 | | rb | 以二進位制格式開啟一個檔案用於只讀。檔案指標將會放在檔案的開頭。這是預設模式。一般用於非文字檔案如圖片等。 | | r+ | 開啟一個檔案用於讀寫。檔案指標將會放在檔案的開頭。 | | rb+ | 以二進位制格式開啟一個檔案用於讀寫。檔案指標將會放在檔案的開頭。一般用於非文字檔案如圖片等。 | | w | 開啟一個檔案只用於寫入。如果該檔案已存在則開啟檔案,並從開頭開始編輯,即原有內容會被刪除。如果該檔案不存在,建立新檔案。 | | wb | 以二進位制格式開啟一個檔案只用於寫入。如果該檔案已存在則開啟檔案,並從開頭開始編輯,即原有內容會被刪除。如果該檔案不存在,建立新檔案。一般用於非文字檔案如圖片等。 | | w+ | 開啟一個檔案用於讀寫。如果該檔案已存在則開啟檔案,並從開頭開始編輯,即原有內容會被刪除。如果該檔案不存在,建立新檔案。 | | wb+ | 以二進位制格式開啟一個檔案用於讀寫。如果該檔案已存在則開啟檔案,並從開頭開始編輯,即原有內容會被刪除。如果該檔案不存在,建立新檔案。一般用於非文字檔案如圖片等。 | | a | 開啟一個檔案用於追加。如果該檔案已存在,檔案指標將會放在檔案的結尾。也就是說,新的內容將會被寫入到已有內容之後。如果該檔案不存在,建立新檔案進行寫入。 | | ab | 以二進位制格式開啟一個檔案用於追加。如果該檔案已存在,檔案指標將會放在檔案的結尾。也就是說,新的內容將會被寫入到已有內容之後。如果該檔案不存在,建立新檔案進行寫入。 | | a+ | 開啟一個檔案用於讀寫。如果該檔案已存在,檔案指標將會放在檔案的結尾。檔案開啟時會是追加模式。如果該檔案不存在,建立新檔案用於讀寫。 | | ab+ | 以二進位制格式開啟一個檔案用於追加。如果該檔案已存在,檔案指標將會放在檔案的結尾。如果該檔案不存在,建立新檔案用於讀寫。 | ```python= with open('test.txt') as file: # 開啟目前目錄下的test.txt檔案並 psss ``` > > > **補充:** > > 開啟檔案時可以相對路徑或絕對路徑指定檔案位置。 #### 檔案編碼 若沒有指定encoding參數,開檔時將採用 `locale.getpreferredencoding()` 的編碼設定,如果要強制指定使用UTF-8編碼,可以加上`encoding`參數來指定編碼,例如: ```python= open('text.txt', encoding='uff-8') ``` #### 讀取檔案 ##### ㄧ次讀取全部檔案內容 ```python= with open('test.txt') as file: content = file.read() # 一次讀取全部檔案內容 print(content) ``` ##### 逐行讀取檔案內容 ```python= with open('test.txt') as file: for line in file: print(line) ``` 另一種方式(使用`readlines()`方法) ```python= with open('test.txt') as file: lines = file.readlines() for line in lines: print(line) ``` #### 寫入檔案 當呼叫`open()`函式打開檔案時,預設只能讀取內容而無法寫入,因此如果要寫入內容到檔案,需要指定「w」模式才能人入資料到檔案。 ##### 開啟檔案為寫入模式(會清空原檔案內容) ```python= with open('test.txt', 'w') as file: pass ``` ##### 開啟檔案為寫入模式(檔案內容會附加到原始檔案後面) ```python= with open('test.txt', 'a') as file: pass ``` ##### 寫入字串到檔案 ```python= with open('test.txt', 'w') as file: file.write('Hello') file.write(' Python') ``` > **補充:** > > 如果要寫入多行資料,需要加上「`\n`」來換行 ## 檔案操作 #### shutil模組 Python提供了shutile用來操作檔案的複製、刪除、移動與修改名稱等等操作,要進行這些操作前需要引入shutil模組: ```python= import shutil ``` #### 檔案複製 ```python= import shutil shutil.copy('a.txt', 'b.txt') # 將目前目錄下的a.txt檔案複製為b.txt ``` #### 目錄複製 ```python= import shutil shutil.copytree('a', 'b') # 將目前目錄下的a目錄複製成b目錄 ``` - 來源目錄要存在,否則會產生例外並結束程式 - 可使用相對路徑或絕對路徑 - 目錄下的子目錄和檔案都會一併被複製到新目錄下 #### 檔案移動 ```python= import shutil shutil.move('a.txt', 'D:\\Documents') # 將目前目錄下的a.txt搬移到D:\Documents目錄下 shutil.move('a.txt', 'D:\\Documents\b.txt') # 將目前目錄下的a.txt搬移到D:\Documents目錄下,並改名為b.txt ``` > **補充:** > > 在移動的過程中如果目的路徑有包含檔案名稱,則會一併修改檔案名稱 #### 目錄移動 `move()`函式也可以用來進行目錄的移動 ```python= import shutil shutil.move('my-dir', 'D:\\Documents') # 將目前目錄下的my-dir子目錄移動到D:\Documents下 shutil.move('my-dir', 'D:\\Documents\my-dir-2') # 將目前目錄下的my-dir子目錄移動到D:\Documents下,並改名為my-dir-2 ``` > **補充:** > > 如果目的地的目錄不存在,則會將原始目錄更名為該名稱,達到改變目錄名稱的效果。 #### 刪除空目錄 ```python= import shutil shutil.rmdir('hello') # 刪除hello這個空目錄 ``` > **補充:** > > 如果要刪除的目錄不是空的,則會刪除失敗。 #### 刪除目錄和底下的所有內容 ```python= import shutil shutil.rmtree('hello') # 刪除hello目錄和底下所有的子目錄和檔案 ``` > **注意:** > > 刪除後無法復原,請小心使用。 ## 練習 1. 列出指定目錄下所有檔案的大小總和。 2. 將指定目錄下的文字檔檔名前面都加上編號,例如: ``` a.txt tr.txt obc.txt ``` 變成: ``` 01-a.txt 02-tr.txt 03-obc.txt ```