Python文件操作

獲取目錄列表

假設你當前的工作目錄有一個叫 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語句,在完成提取後,存檔文件會自動關閉。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章