獲取目錄列表
假設你當前的工作目錄有一個叫 my_directory 的子目錄,該目錄包含如下內容:
├── file1.py
├── file2.csv
├── file3.txt
├── sub_dir
│ ├── bar.py
│ └── foo.py
├── sub_dir_b
│ └── file4.txt
└── sub_dir_c
├── config.py
└── file5.txt
Python內置的 os 模塊
有很多有用的方法能被用來列出目錄內容和過濾結果。爲了獲取文件系統中特定目錄的所有文件和文件夾列表,可以在遺留版本的Python中使用 os.listdir()
或 在Python 3.x 中使用 os.scandir()
。 如果你還想獲取文件和目錄屬性(如文件大小和修改日期),那麼 os.scandir() 則是首選的方法。
使用遺留版本的Python獲取目錄列表
import os
entries = os.listdir('my_directory')
os.listdir() 返回一個Python列表,其中包含path參數所指目錄的文件和子目錄的名稱。
[‘file1.py’, ‘file2.csv’, ‘file3.txt’, ‘sub_dir’, ‘sub_dir_b’, ‘sub_dir_c’]
目錄列表現在看上去不容易閱讀,對 os.listdir() 的調用結果使用循環打印有助於查看。
for entry in entries:
print(entry)
使用現代版本的Python獲取目錄列表
在現代Python版本中,可以使用os.scandir()
和 pathlib.Path
來替代 os.listdir()
。
os.scandir()
調用時返回一個迭代器而不是一個列表。
import os
entries = os.scandir('my_directory')
print(entries)
# <posix.ScandirIterator at 0x105b4d4b0>
ScandirIterator 指向了當前目錄中的所有條目。你可以遍歷迭代器的內容,並打印文件名。
import os
with os.scandir('my_directory') as entries:
for entry in entries:
print(entry.name)
另一個獲取目錄列表的方法是使用pathlib 模塊
:
from pathlib import Path
entries = Path('my_directory')
for entry in entries.iterdir():
print(entry.name)
pathlib.Path() 返回的是 PosixPath 或 WindowsPath 對象,這取決於操作系統。
pathlib.Path() 對象有一個 .iterdir() 的方法用於創建一個迭代器包含該目錄下所有文件和目錄。由 .iterdir() 生成的每個條目都包含文件或目錄的信息,例如其名稱和文件屬性。
在上面的例子中,你調用 pathlib.Path() 並傳入了一個路徑參數。然後調用 .iterdir() 來獲取 my_directory 下的所有文件和目錄列表。
| os.listdir() | 以列表的方式返回目錄中所有的文件和文件夾 | | os.scandir() | 返回一個迭代器包含目錄中所有的對象,對象包含文件屬性信息 | | pathlib.Path().iterdir() | 返回一個迭代器包含目錄中所有的對象,對象包含文件屬性信息 |
列出目錄中的所有文件
如何使用 os.listdir()
,os.scandir()
和 pathlib.Path()
打印出目錄中文件的名稱。爲了過濾目錄並僅列出 os.listdir()
生成的目錄列表的文件,要使用 os.path
:
import os
basepath = 'my_directory'
for entry in os.listdir(basepath):
# 使用os.path.isfile判斷該路徑是否是文件類型
if os.path.isfile(os.path.join(base_path, entry)):
print(entry)
在這裏調用 os.listdir()
返回指定路徑中所有內容的列表,接着使用os.path.isfile()
過濾列表讓其只顯示文件類型而非目錄類型。
輸出:
file1.py
file2.csv
file3.txt
一個更簡單的方式來列出一個目錄中所有的文件是使用 os.scandir()
或 pathlib.Path()
:
import os
basepath = 'my_directory'
with os.scandir(basepath) as entries:
for entry in entries:
if entry.is_file():
print(entry.name)
如何使用 pathlib.Path() 列出一個目錄中的文件:
basepath = Path('my_directory')
for entry in basepath.iterdir():
if entry.is_file():
print(entry.name)
列出子目錄
如果要列出子目錄而不是文件,請使用下面的方法。現在展示如何使用 os.listdir()
和 os.path()
:
basepath = 'my_directory'
for entry in os.listdir(basepath):
if os.path.isdir(os.path.join(basepath, entry)):
print(entry)
使用 os.scandir() :
import os
basepath = 'my_directory'
with os.scandir(basepath) as entries:
for entry in entries:
if entry.is_dir():
print(entry.name)
使用 pathlib.Path()
:
basepath = Path('my_directory')
for entry in basepath.iterdir():
if entry.is_dir():
print(entry.name)
輸出:
sub_dir_c
sub_dir_b
sub_dir
獲取文件屬性
Python可以很輕鬆的獲取文件大小和修改時間等文件屬性。可以通過使用 os.stat()
, os.scandir()
或 pathlib.Path
來獲取。
os.scandir()
和 pathlib.Path()
能直接獲取到包含文件屬性的目錄列表。這可能比使用 os.listdir()
列出文件然後獲取每個文件的文件屬性信息更加有效。
下面的例子顯示瞭如何獲取 my_directory 中文件的最後修改時間()。以時間戳的方式輸出:
import os
with os.scandir('my_directory') as entries:
for entry in entries:
info = entry.stat()
print(info.st_mtime)
pathlib 模塊具有相應的方法,用於獲取相同結果的文件信息:
from pathlib import Path
basepath = Path('my_directory')
for entry in basepath.iterdir():
info = entry.stat()
print(info.st_mtime)
創建目錄
你編寫的程序遲早需要創建目錄以便在其中存儲數據。 os 和 pathlib 包含了創建目錄的函數。
os.mkdir()
| 創建單個子目錄 | |
os.makedirs()
| 創建多個目錄,包括中間目錄 | | Pathlib.Path.mkdir()
| 創建單個或多個目錄 |
import os
os.mkdir('example_directory')
如果該目錄已經存在,os.mkdir()
將拋出 FileExistsError 異常。或者,你也可以使用 pathlib
來創建目錄:
from pathlib import Path
p = Path('example_directory')
p.mkdir()
如果路徑已經存在,mkdir()
會拋出 FileExistsError 異常:
FileExistsError: [Errno 17] File exists: 'example_directory'
爲了避免像這樣的錯誤拋出, 當發生錯誤時捕獲錯誤並讓你的用戶知道:
from pathlib import Path
p = Path('example_directory')
try:
p.mkdir()
except FileExistsError as e:
print(e)
創建多個目錄
os.makedirs()
和os.mkdir()
類似。兩者之間的區別在於,os.makedirs()
不僅可以創建單獨的目錄,還可以遞歸的創建目錄樹。換句話說,它可以創建任何必要的中間文件夾,來確保存在完整的路徑。
import os
os.makedirs('2018/10/05', mode=0o770)
文件名模式匹配
使用上述方法之一獲取目錄中的文件列表後,你可能希望搜索和特定的模式匹配的文件。
endswith() 和 startswith()
字符串方法
fnmatch.fnmatch()
glob.glob()
pathlib.Path.glob()
使用字符串方法
Python有幾個內置 修改和操作字符串 的方法。當在匹配文件名時,其中的兩個方法 .startswith()
和 .endswith()
非常有用。要做到這點,首先要獲取一個目錄列表,然後遍歷。
import os
for f_name in os.listdir('some_directory'):
if f_name.endswith('.txt'):
print(f_name)
使用 fnmatch
進行簡單文件名模式匹配
字符串方法匹配的能力是有限的。fnmatch
有對於模式匹配有更先進的函數和方法。我們將考慮使用 fnmatch.fnmatch()
,這是一個支持使用*
和 ?
等通配符的函數。例如,使用 fnmatch 查找目錄中所有 .txt 文件,你可以這樣做:
import os
import fnmatch
for f_name in os.listdir('some_directory'):
if fnmatch.fnmatch(f_name, '*.txt'):
print(f_name)
更先進的模式匹配
假設你想要查找符合特定掉件的 .txt 文件。例如,你可能指向找到包含單次 data 的 .txt文件,一組下劃線之間的數字,以及文件名中包含單詞 backup 。就類似於 data_01_backup, data_02_backup, 或 data_03_backup 。
import os
import fnmatch
for f_name in os.listdir('some_directory'):
if fnmatch.fnmatch(f_name, 'data_*_backup.txt'):
print(f_name)
這裏就僅僅打印出匹配 data_*_backup.txt 模式的文件名稱。模式中的 * 將匹配任何字符,因此運行這段代碼則將查找文件名以 data 開頭並以 backup.txt 的所有文本文件,就行下面的輸出所示 :
data_01_backup.txt
data_02_backup.txt
data_03_backup.txt
遍歷目錄和處理文件
一個常見的編程任務是遍歷目錄樹並處理目錄樹中的文件。讓我們來探討一下如何使用內置的Python函數 os.walk()
來實現這一功能。os.walk()
用於通過從上到下或從下到上遍歷樹來生成目錄樹中的文件名。處於本節的目的,我們想操作以下的目錄樹:
import os
for dirpath, dirname, files in os.walk('.'):
print(f'Found directory: {dirpath}')
for file_name in files:
print(file_name)
os.walk() 在每個循環中返回三個值:
當前文件夾的名稱
當前文件夾中子文件夾的列表
當前文件夾中文件的列表
在每次迭代中,會打印出它找到的子目錄和文件的名稱:
Found directory: .
test1.txt
test2.txt
Found directory: ./folder_1
file1.py
file3.py
file2.py
Found directory: ./folder_2
file4.py
file5.py
file6.py
複製、移動和重命名文件和目錄
Python附帶了shutil 模塊
。shutil
是shell實用程序的縮寫。 它爲文件提供了許多高級操作,來支持文件和目錄的複製,歸檔和刪除。 在本節中,你將學習如何移動和複製文件和目錄。
複製文件:
shutil 提供了一些複製文件的函數。 最常用的函數是 shutil.copy()
和 shutil.copy2()
。 使用shutil.copy()
將文件從一個位置複製到另一個位置,請執行以下操作:
import shutil
src = 'path/to/file.txt'
dst = 'path/to/dest_dir'
shutil.copy(src, dst)
shutil.copy(src,dst) 會將文件 src 複製到 dst 中指定的位置。 如果 dst 是文件,則該文件的內容將替換爲 src 的內容。 如果 dst 是目錄,則 src 將被複制到該目錄中。 shutil.copy() 僅複製文件的內容和文件的權限。 其他元數據(如文件的創建和修改時間)不會保留。
要在複製時保留所有文件元數據,請使用 shutil.copy2()
:
import shutil
src = 'path/to/file.txt'
dst = 'path/to/dest_dir'
shutil.copy2(src, dst)
複製目錄
雖然 shutil.copy() 只複製單個文件,但 shutil.copytree() 將複製整個目錄及其中包含的所有內容。 shutil.copytree(src,dest)
接收兩個參數:源目錄和將文件和文件夾複製到的目標目錄。
以下是如何將一個文件夾的內容複製到其他位置的示例:
import shutil
dst = shutil.copytree('data_1', 'data1_backup')
print(dst) # data1_backup
在此示例中,.copytree()
將 data_1 的內容複製到新位置 data1_backup 並返回目標目錄。 目標目錄不能是已存在的。 它將被創建而不帶有其父目錄。 shutil.copytree() 是備份文件的一個好方法。
移動文件和目錄
要將文件或目錄移動到其他位置,請使用 shutil.move(src,dst)
。
src 是要移動的文件或目錄,dst 是目標:
import shutil
dst = shutil.move('dir_1/', 'backup/')
print(dst) # 'backup'
如果 backup/ 存在,則 shutil.move(‘dir_1/’,‘backup/’) 將 dir_1/ 移動到 backup/ 。 如果 backup/ 不存在,則 dir_1/ 將重命名爲 backup 。
重命名文件和目錄
Python包含用於重命名文件和目錄的os.rename(src,dst)
:
import os
os.rename('first.zip', 'first_01.zip')
上面的行將 first.zip 重命名爲 first_01.zip 。 如果目標路徑指向目錄,則會拋出 OSError 。
重命名文件或目錄的另一種方法是使用 pathlib 模塊中的 rename():
from pathlib import Path
data_file = Path('data_01.txt')
data_file.rename('data.txt')
讀取ZIP文件
zipfile 模塊
是一個底層模塊,是Python標準庫的一部分。 zipfile 具有可以輕鬆打開和提取ZIP文件的函數。 要讀取ZIP文件的內容,首先要做的是創建一個 ZipFile 對象。ZipFile 對象類似於使用 open() 創建的文件對象。ZipFile 也是一個上下文管理器,因此支持with語句:
import zipfile
with zipfile.ZipFile('data.zip', 'r') as zipobj:
pass
這裏創建一個ZipFile 對象
,傳入ZIP文件的名稱並以讀取模式下打開。 打開ZIP文件後,可以通過 zipfile 模塊
提供的函數訪問有關存檔文件的信息。 上面示例中的 data.zip 存檔是從名爲 data 的目錄創建的,該目錄包含總共5個文件和1個子目錄:
要獲取存檔文件中的文件列表,請在 ZipFile 對象上調用 namelist()
:
import zipfile
with zipfile.ZipFile('data.zip', 'r') as zipobj:
zipobj.namelist()
這會生成一個文件列表:
[‘file1.py’, ‘file2.py’, ‘file3.py’, ‘sub_dir/’, ‘sub_dir/bar.py’, ‘sub_dir/foo.py’]
.namelist()
返回存檔文件中文件和目錄的名稱列表。要檢索有關存檔文件中文件的信息,使用 .getinfo()
:
import zipfile
with zipfile.ZipFile('data.zip', 'r') as zipobj:
bar_info = zipobj.getinfo('sub_dir/bar.py')
print(bar_info.file_size)
提取ZIP文件
zipfile 模塊允許你通過.extract()
和 .extractall()
從ZIP文件中提取一個或多個文件。
默認情況下,這些方法將文件提取到當前目錄。 它們都採用可選的路徑參數,允許指定要將文件提取到的其他指定目錄。 如果該目錄不存在,則會自動創建該目錄。 要從壓縮文件中提取文件,請執行以下操作:
>>> import zipfile
>>> import os
>>> os.listdir('.')
['data.zip']
>>> data_zip = zipfile.ZipFile('data.zip', 'r')
>>> # 提取單個文件到當前目錄
>>> data_zip.extract('file1.py')
'/home/test/dir1/zip_extract/file1.py'
>>> os.listdir('.')
['file1.py', 'data.zip']
>>> # 提所有文件到指定目錄
>>> data_zip.extractall(path='extract_dir/')
>>> os.listdir('.')
['file1.py', 'extract_dir', 'data.zip']
>>> os.listdir('extract_dir')
['file1.py', 'file3.py', 'file2.py', 'sub_dir']
>>> data_zip.close()
第三行代碼是對 os.listdir() 的調用,它顯示當前目錄只有一個文件 data.zip 。
接下來,以讀取模式下打開 data.zip 並調用 .extract() 從中提取 file1.py 。 .extract() 返回提取文件的完整文件路徑。 由於沒有指定路徑,.extract() 會將 file1.py 提取到當前目錄。
下一行打印一個目錄列表,顯示當前目錄現在包括除原始存檔文件之外的存檔文件。 之後顯示瞭如何將整個存檔提取到指定目錄中。.extractall() 創建 extract_dir 並將 data.zip 的內容提取到其中。 最後一行關閉ZIP存檔文件。
從加密的文檔提取數據
zipfile 支持提取受密碼保護的ZIP。 要提取受密碼保護的ZIP文件,請將密碼作爲參數傳遞給 .extract() 或.extractall() 方法:
>>> import zipfile
>>> with zipfile.ZipFile('secret.zip', 'r') as pwd_zip:
... # 從加密的文檔提取數據
... pwd_zip.extractall(path='extract_dir', pwd='Quish3@o')
將以讀取模式打開 secret.zip 存檔。 密碼提供給 .extractall() ,並且壓縮文件內容被提取到 extract_dir 。 由於with語句,在完成提取後,存檔文件會自動關閉。