虛擬環境的搭建&pycharm的使用
轉載:https://zhuanlan.zhihu.com/p/56909212?utm_source=wechat_session
原文:https://realpython.com/working-with-files-in-python/
Python中有幾個內建模組和方法來處理檔案。這些方法被分割到例如os
,os.path
,shutil
和pathlib
等等幾個模組中。文章將列舉Python中對檔案最常用的操作和方法。
在這篇文章中,你將學習如何:
- 獲取檔案屬性
- 建立目錄
- 檔名模式匹配
- 遍歷目錄樹
- 建立臨時檔案和目錄
- 刪除檔案和目錄
- 複製、移動和重新命名檔案和目錄
- 建立和解壓ZIP和TAR檔案
- 使用
fileinput
Python中檔案資料的讀和寫
使用Python對檔案進行讀和寫是十分簡單的。為此,你首先必須使用合適的模式開啟檔案。這裡有一個如何開啟文字檔案並讀取其內容的例子。
with open('data.txt', 'r') as f:
data = f.read()
print('context: {}'.format(data))
open()
接收一個檔名和一個模式作為它的引數,r
表示以只讀模式開啟檔案。想要往檔案中寫資料的話,則用w
作為引數。
with open('data.txt', 'w') as f:
data = 'some data to be written to the file'
f.write(data)
在上述例子中,open()開啟用於讀取或寫入的檔案並返回檔案控制代碼(本例子中的f
),該控制代碼提供了可用於讀取或寫入檔案資料的方法。閱讀Working With File I/O in 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)
"""
file1.py
file2.csv
file3.txt
sub_dir
sub_dir_b
sub_dir_c
"""
使用現代版本的Python獲取目錄列表
在現代Python版本中,可以使用os.scandir()
和pathlib.Path
來替代os.listdir()
。
os.scandir()
在Python 3.5 中被引用,其文件為PEP 471。
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)
這裡os.scandir()
和with語句一起使用,因為它支援上下文管理協議。使用上下文管理器關閉迭代器並在迭代器耗盡後自動釋放獲取的資源。在my_directory
列印檔名的結果就和在os.listdir()
例子中看到的一樣:
file1.py
file2.csv
file3.txt
sub_dir
sub_dir_b
sub_dir_c
另一個獲取目錄列表的方法是使用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
在Python3.4時被第一次引入,並且是對Python一個很好的加強,它為檔案系統提供了面向物件的介面。
在上面的例子中,你呼叫pathlib.Path()
並傳入了一個路徑引數。然後呼叫.iterdir()
來獲取my_directory
下的所有檔案和目錄列表。
pathlib
提供了一組類,以簡單並且面向物件的方式提供了路徑上的大多數常見的操作。使用pathlib
比起使用os
中的函式更加有效。和os
相比,使用pathlib
的另一個好處是減少了操作檔案系統路徑所匯入包或模組的數量。想要了解更多資訊,可以閱讀Python 3’s pathlib Module: Taming the File System。
執行上述程式碼會得到如下結果:
file1.py
file2.csv
file3.txt
sub_dir
sub_dir_b
sub_dir_c
使用pathlib.Path()
或os.scandir()
來替代os.listdir()
是獲取目錄列表的首選方法,尤其是當你需要獲取檔案型別和檔案屬性資訊的時候。pathlib.Path()
提供了在os
和shutil
中大部分處理檔案和路徑的功能,並且它的方法比這些模組更加有效。我們將討論如何快速的獲取檔案屬性。
| 函式 | 描述 | | ------------------------ | -------------------------------------------------------- | | 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)
使用os.scandir()
比起os.listdir()
看上去更清楚和更容易理解。對ScandirIterator
的每一項呼叫entry.isfile()
,如果返回True
則表示這一項是一個檔案。上述程式碼的輸出如下:
file1.py
file3.txt
file2.csv
接著,展示如何使用pathlib.Path()
列出一個目錄中的檔案:
from pathlib import Path
basepath = Path('my_directory')
for entry in basepath.iterdir():
if entry.is_file():
print(entry.name)
在.iterdir()
產生的每一項呼叫.is_file()
。產生的輸出結果和上面相同:
file1.py
file3.txt
file2.csv
如果將for迴圈和if語句組合成單個生成器表示式,則上述的程式碼可以更加簡潔。關於生成器表示式,推薦一篇Dan Bader的文章。
修改後的版本如下:
from pathlib import Path
basepath = Path('my_directory')
files_in_basepath = (entry for entry in basepath.iterdir() if entry.is_file())
for item in files_in_basepath:
print(item.name)
上述程式碼的執行結果和之前相同。本節展示使用os.scandir()
和pathlib.Path()
過濾檔案或目錄比使用os.listdir()
和os.path
更直觀,程式碼看起來更簡潔。
列出子目錄
如果要列出子目錄而不是檔案,請使用下面的方法。現在展示如何使用os.listdir()
和os.path()
:
import os
basepath = 'my_directory'
for entry in os.listdir(basepath):
if os.path.isdir(os.path.join(basepath, entry)):
print(entry)
當你多次呼叫os.path,join()
時,以這種方式操作檔案系統就會變得很笨重。在我電腦上執行此程式碼會產生以下輸出:
sub_dir
sub_dir_b
sub_dir_c
下面是如何使用os.scandir()
:
import os
basepath = 'my_directory'
with os.scandir(basepath) as entries:
for entry in entries:
if entry.is_dir():
print(entry.name)
與檔案列表中的示例一樣,此處在os.scandir()
返回的每一項上呼叫.is_dir()
。如果這項是目錄,則is_dir()
返回 True,並打印出目錄的名稱。輸出結果和上面相同:
sub_dir_c
sub_dir_b
sub_dir
下面是如何使用pathlib.Path()
:
from pathlib import Path
basepath = Path('my_directory')
for entry in basepath.iterdir():
if entry.is_dir():
print(entry.name)
在.iterdir()
迭代器返回的每一項上呼叫is_dir()
檢查是檔案還是目錄。如果該項是目錄,則列印其名稱,並且生成的輸出與上一示例中的輸出相同:
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)
"""
1548163662.3952665
1548163689.1982062
1548163697.9175904
1548163721.1841028
1548163740.765162
1548163769.4702623
"""
os.scandir()
返回一個ScandirIterator
物件。ScandirIterator
物件中的每一項有.stat()
方法能獲取關於它指向檔案或目錄的資訊。.stat()
提供了例如檔案大小和最後修改時間的資訊。在上面的示例中,程式碼列印了st_time
屬性,該屬性是上次修改檔案內容的時間。
pathlib
模組具有相應的方法,用於獲取相同結果的檔案資訊:
from pathlib import Path
basepath = Path('my_directory')
for entry in basepath.iterdir():
info = entry.stat()
print(info.st_mtime)
"""
1548163662.3952665
1548163689.1982062
1548163697.9175904
1548163721.1841028
1548163740.765162
1548163769.4702623
"""
在上面的例子中,迴圈.iterdir()
返回的迭代器並通過對其中每一項呼叫.stat()
來獲取檔案屬性。st_mtime
屬性是一個浮點型別的值,表示的是時間戳。為了讓st_time
返回的值更容易閱讀,你可以編寫一個輔助函式將其轉換為一個datetime
物件:
import datetime
from pathlib import Path
def timestamp2datetime(timestamp, convert_to_local=True, utc=8, is_remove_ms=True)
"""
轉換 UNIX 時間戳為 datetime物件
:param timestamp: 時間戳
:param convert_to_local: 是否轉為本地時間
:param utc: 時區資訊,中國為utc+8
:param is_remove_ms: 是否去除毫秒
:return: datetime 物件
"""
if is_remove_ms:
timestamp = int(timestamp)
dt = datetime.datetime.utcfromtimestamp(timestamp)
if convert_to_local:
dt = dt + datetime.timedelta(hours=utc)
return dt
def convert_date(timestamp, format='%Y-%m-%d %H:%M:%S'):
dt = timestamp2datetime(timestamp)
return dt.strftime(format)
basepath = Path('my_directory')
for entry in basepath.iterdir():
if entry.is_file()
info = entry.stat()
print('{} 上次修改時間為 {}'.format(entry.name, timestamp2datetime(info.st_mtime)))
首先得到my_directory
中檔案的列表以及它們的屬性,然後呼叫convert_date()
來轉換檔案最後修改時間讓其以一種人類可讀的方式顯示。convert_date()
使用.strftime()
將datetime型別轉換為字串。
上述程式碼的輸出結果:
file3.txt 上次修改時間為 2019-01-24 09:04:39
file2.csv 上次修改時間為 2019-01-24 09:04:39
file1.py 上次修改時間為 2019-01-24 09:04:39
將日期和時間轉換為字串的語法可能會讓你感到混亂。如果要了解更多的資訊,請查詢相關的官方文件。另一個方式則是閱讀http://strftime.org。
建立目錄
你編寫的程式遲早需要建立目錄以便在其中儲存資料。os
和pathlib
包含了建立目錄的函式。我們將會考慮如下方法:
| 方法 | 描述 | | -------------------- | -------------------------- | | os.mkdir() | 建立單個子目錄 | | os.makedirs() | 建立多個目錄,包括中間目錄 | | Pathlib.Path.mkdir() | 建立單個或多個目錄 |
建立單個目錄
要建立單個目錄,把目錄路徑作為引數傳給os.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)
或者,你可以給.mkdir()
傳入exist_ok=True
引數來忽略FileExistsError
異常:
from pathlib import Path
p = Path('example_directory')
p.mkdir(exist_ok=True)
如果目錄已存在,則不會引起錯誤。
建立多個目錄
os.makedirs()
和os.mkdir()
類似。兩者之間的區別在於,os.makedirs()
不僅可以建立單獨的目錄,還可以遞迴的建立目錄樹。換句話說,它可以建立任何必要的中間資料夾,來確保存在完整的路徑。
os.makedirs()
和在bash中執行mkdir -p
類似。例如,要建立一組目錄像 2018/10/05,你可以像下面那樣操作:
import os
os.makedirs('2018/10/05', mode=0o770)
上述程式碼建立了2018/10/05
的目錄結構併為所有者和組使用者提供讀、寫和執行許可權。預設的模式為0o777
,增加了其他使用者組的許可權。有關檔案許可權以及模式的應用方式的更多詳細資訊,請參考文件。
執行tree
命令確認我們應用的許可權:
$ tree -p -i .
.
[drwxrwx---] 2018
[drwxrwx---] 10
[drwxrwx---] 05
上述程式碼打印出當前目錄的目錄樹。tree
通常被用來以樹形結構列出目錄的內容。傳入-p
和-i
引數則會以垂直列表打印出目錄名稱以及其檔案許可權資訊。-p
用於輸出檔案許可權,-i
則用於讓tree
命令產生一個沒有縮排線的垂直列表。
正如你所看到的,所有的目錄都擁有 770 許可權。另一個方式建立多個目錄是使用pathlib.Path
的.mkdir()
:
from pathlib import Path
p = Path('2018/10/05')
p.mkdir(parents=True, exist_ok=True)
通過給Path.mkdir()
傳遞parents=True
關鍵字引數使它建立05
目錄和使其路徑有效的所有父級目錄。
在預設情況下,os.makedirs()
和pathlib.Path.mkdir()
會在目標目錄存在的時候丟擲OSError
。通過每次呼叫函式時傳遞exist_ok=True
作為關鍵字引數則可以覆蓋此行為(從Python3.2開始)。
執行上述程式碼會得到像下面的結構:
└── 2018
└── 10
└── 05
我更喜歡在建立目錄時使用pathlib
,因為我可以使用相同的函式方法來建立一個或多個目錄。
檔名模式匹配
使用上述方法之一獲取目錄中的檔案列表後,你可能希望搜尋和特定的模式匹配的檔案。
下面這些是你可以使用的方法和函式:
endswith()
和startswith()
字串方法fnmatch.fnmatch()
glob.glob()
pathlib.Path.glob()
這些方法和函式是下面要討論的。本小節的示例將在名為some_directory
的目錄下執行,該目錄具有以下的結構:
.
├── admin.py
├── data_01_backup.txt
├── data_01.txt
├── data_02_backup.txt
├── data_02.txt
├── data_03_backup.txt
├── data_03.txt
├── sub_dir
│ ├── file1.py
│ └── file2.py
└── tests.py
如果你正在使用 Bash shell,你可以使用以下的命令建立上述目錄結構:
mkdir some_directory
cd some_directory
mkdir sub_dir
touch sub_dir/file1.py sub_dir/file2.py
touch data_{01..03}.txt data_{01..03}_backup.txt admin.py tests.py
這將會建立some_directory
目錄並進入它,接著建立sub_dir
。下一行在sub_dir
建立file1.py
和file2.py
,最後一行使用擴充套件建立其它所有檔案。想要學習更多關於shell擴充套件,請閱讀這裡。
使用字串方法
Python有幾個內建修改和操作字串的方法。當在匹配檔名時,其中的兩個方法.startswith()
和.endswith()
非常有用。要做到這點,首先要獲取一個目錄列表,然後遍歷。
import os
for f_name in os.listdir('some_directory'):
if f_name.endswith('.txt'):
print(f_name)
上述程式碼找到some_directory
中的所有檔案,遍歷並使用.endswith()
來列印所有副檔名為.txt
的檔名。執行程式碼在我的電腦上輸出如下:
data_01.txt
data_01_backup.txt
data_02.txt
data_02_backup.txt
data_03.txt
data_03_backup.txt
使用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)
迭代some_directory
中的檔案列表,並使用.fnmatch()
對副檔名為.txt
的檔案執行萬用字元搜尋。
更先進的模式匹配
假設你想要查詢符合特定掉件的.txt
檔案。例如,你可能指向找到包含單次data
的.txt
檔案,一組下劃線之間的數字,以及檔名中包含單詞backup
。就類似於data_01_backup
,data_02_backup
, 或data_03_backup
。
你可以這樣使用fnmatch.fnmatch()
:
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
使用glob
進行檔名模式匹配
另一個有用的模式匹配模組是glob
。
.glob()
在glob
模組中的左右就像fnmatch.fnmatch()
,但是與fnmach.fnmatch()
不同的是,它將以.
開頭的檔案視為特殊檔案。
UNIX和相關係統在檔案列表中使用萬用字元像?
和*
表示全匹配。
例如,在UNIX shell中使用mv *.py python_files
移動所有.py
副檔名 的檔案從當前目錄到python_files
。這*
是一個萬用字元表示任意數量的字元,*.py
是一個全模式。Windows作業系統中不提供此shell功能。但glob
模組在Python中添加了此功能,使得Windows程式可以使用這個特性。
這裡有一個使用glob
模組在當前目錄下查詢所有Python程式碼檔案:
import glob
print(glob.glob('*.py'))
glob.glob('*.py')
搜尋當前目錄中具有.py
副檔名的檔案,並且將它們以列表的形式返回。glob
還支援 shell 樣式的萬用字元來進行匹配 :
import glob
for name in glob.glob('*[0-9]*.txt'):
print(name)
這將找到所有檔名中包含數字的文字檔案(.txt
) :
data_01.txt
data_01_backup.txt
data_02.txt
data_02_backup.txt
data_03.txt
data_03_backup.txt
glob
也很容易在子目錄中遞迴的搜尋檔案:
import glob
for name in glob.iglob('**/*.py', recursive=True):
print(name)
這裡例子使用了glob.iglob()
在當前目錄和子目錄中搜索所有的.py
檔案。傳遞recursive=True
作為.iglob()
的引數使其搜尋當前目錄和子目錄中的.py
檔案。glob.glob()
和glob.iglob()
不同之處在於,iglob()
返回一個迭代器而不是一個列表。
執行上述程式碼會得到以下結果:
admin.py
tests.py
sub_dir/file1.py
sub_dir/file2.py
pathlib
也包含類似的方法來靈活的獲取檔案列表。下面的例子展示了你可以使用.Path.glob()
列出以字母p
開始的檔案型別的檔案列表。
from pathlib import Path
p = Path('.')
for name in p.glob('*.p*'):
print(name)
呼叫p.glob('*.p*')
會返回一個指向當前目錄中所有副檔名以字母p
開頭的檔案的生成器物件。
Path.glob()
和上面討論過的os.glob()
類似。正如你看到的,pathlib
混合了許多os
,os.path
和glob
模組的最佳特性到一個模組中,這使得使用起來很方便。
回顧一下,這是我們在本節中介紹的功能表:
| 函式 | 描述 | | ---------------------------------- | ---------------------------------------------------------- | | startswith() | 測試一個字串是否以一個特定的模式開始,返回 True 或 False | | endswith() | 測試一個字串是否以一個特定的模式結束,返回 True 或 False | | fnmatch.fnmatch(filename, pattern) | 測試檔名是否匹配這個模式,返回 True 或 False | | glob.glob() | 返回一個匹配該模式的檔名列表 | | pathlib.Path.glob() | 返回一個匹配該模式的生成器物件 |
遍歷目錄和處理檔案
一個常見的程式設計任務是遍歷目錄樹並處理目錄樹中的檔案。讓我們來探討一下如何使用內建的Python函式os.walk()
來實現這一功能。os.walk()
用於通過從上到下或從下到上遍歷樹來生成目錄樹中的檔名。處於本節的目的,我們想操作以下的目錄樹:
├── folder_1
│ ├── file1.py
│ ├── file2.py
│ └── file3.py
├── folder_2
│ ├── file4.py
│ ├── file5.py
│ └── file6.py
├── test1.txt
└── test2.txt
以下是一個示例,演示如何使用os.walk()
列出目錄樹中的所有檔案和目錄。
os.walk()
預設是從上到下遍歷目錄:
python 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
要以自下而上的方式遍歷目錄樹,則將topdown=False
關鍵字引數傳遞給os.walk()
:
for dirpath, dirnames, files in os.walk('.', topdown=False):
print(f'Found directory: {dirpath}')
for file_name in files:
print(file_name)
傳遞topdown=False
引數將使os.walk()
首先打印出它在子目錄中找到的檔案:
Found directory: ./folder_1
file1.py
file3.py
file2.py
Found directory: ./folder_2
file4.py
file5.py
file6.py
Found directory: .
test1.txt
test2.txt
如你看見的,程式在列出根目錄的內容之前列出子目錄的內容。 這在在你想要遞迴刪除檔案和目錄的情況下非常有用。 你將在以下部分中學習如何執行此操作。 預設情況下,os.walk
不會訪問通過軟連線建立的目錄。 可以通過使用followlinks = True
引數來覆蓋預設行為。
建立臨時檔案和目錄
Python提供了tempfile
模組來便捷的建立臨時檔案和目錄。
tempfile
可以在你程式執行時開啟並存儲臨時的資料在檔案或目錄中。tempfile
會在你程式停止執行後刪除這些臨時檔案。
現在,讓我們看看如何建立一個臨時檔案:
from tempfile import TemporaryFile
# 建立一個臨時檔案併為其寫入一些資料
fp = TemporaryFile('w+t')
fp.write('Hello World!')
# 回到開始,從檔案中讀取資料
fp.seek(0)
data = fp.read()
print(data)
# 關閉檔案,之後他將會被刪除
fp.close()
第一步是從tempfile
模組匯入TemporaryFile
。 接下來,使用TemporaryFile()
方法並傳入一個你想開啟這個檔案的模式來建立一個類似於物件的檔案。這將建立並開啟一個可用作臨時儲存區域的檔案。
在上面的示例中,模式為w + t
,這使得tempfile
在寫入模式下建立臨時文字檔案。 沒有必要為臨時檔案提供檔名,因為在指令碼執行完畢後它將被銷燬。
寫入檔案後,您可以從中讀取並在完成處理後將其關閉。 一旦檔案關閉後,將從檔案系統中刪除。 如果需要命名使用tempfile
生成的臨時檔案,請使用tempfile.NamedTemporaryFile()
。
使用tempfile
建立的臨時檔案和目錄儲存在用於儲存臨時檔案的特殊系統目錄中。 Python將在目錄列表搜尋使用者可以在其中建立檔案的目錄。
在Windows上,目錄按順序為C:\TEMP
,C:\TMP
,\TEMP
和\TMP
。 在所有其他平臺上,目錄按順序為/ tmp
,/var/tmp
和/usr/tmp
。 如果上述目錄中都沒有,tempfile
將在當前目錄中儲存臨時檔案和目錄。
.TemporaryFile()
也是一個上下文管理器,因此它可以與with語句一起使用。 使用上下文管理器會在讀取檔案後自動關閉和刪除檔案:
with TemporaryFile('w+t') as fp:
fp.write('Hello universe!')
fp.seek(0)
fp.read()
# 臨時檔案現在已經被關閉和刪除
這將建立一個臨時檔案並從中讀取資料。 一旦讀取檔案的內容,就會關閉臨時檔案並從檔案系統中刪除。
tempfile
也可用於建立臨時目錄。 讓我們看一下如何使用tempfile.TemporaryDirectory()
來做到這一點:
import tempfile
import os
tmp = ''
with tempfile.TemporaryDirectory() as tmpdir:
print('Created temporary directory ', tmpdir)
tmp = tmpdir
print(os.path.exists(tmpdir))
print(tmp)
print(os.path.exists(tmp))
呼叫tempfile.TemporaryDirectory()
會在檔案系統中建立一個臨時目錄,並返回一個表示該目錄的物件。 在上面的示例中,使用上下文管理器建立目錄,目錄的名稱儲存在tmpdir
變數中。 第三行打印出臨時目錄的名稱,os.path.exists(tmpdir)
來確認目錄是否實際在檔案系統中建立。
在上下文管理器退出上下文後,臨時目錄將被刪除,並且對os.path.exists(tmpdir)
的呼叫將返回False,這意味著該目錄已成功刪除。
刪除檔案和目錄
您可以使用os
,shutil
和pathlib
模組中的方法刪除單個檔案,目錄和整個目錄樹。 以下將介紹如何刪除你不再需要的檔案和目錄。
Python中刪除檔案
要刪除單個檔案,請使用pathlib.Path.unlink()
,os.remove()
或os.unlink()
。
os.remove()
和os.unlink()
在語義上是相同的。 要使用os.remove()
刪除檔案,請執行以下操作:
import os
data_file = 'C:\\Users\\vuyisile\\Desktop\\Test\\data.txt'
os.remove(data_file)
使用os.unlink()
刪除檔案與使用os.remove()
的方式類似:
import os
data_file = 'C:\\Users\\vuyisile\\Desktop\\Test\\data.txt'
os.unlink(data_file)
在檔案上呼叫.unlink()
或.remove()
會從檔案系統中刪除該檔案。 如果傳遞給它們的路徑指向目錄而不是檔案,這兩個函式將丟擲OSError
。 為避免這種情況,可以檢查你要刪除的內容是否是檔案,並在確認是檔案時執行刪除操作,或者可以使用異常處理來處理OSError
:
import os
data_file = 'home/data.txt'
# 如果型別是檔案則進行刪除
if os.path.is_file(data_file):
os.remove(data_file)
else:
print(f'Error: {data_file} not a valid filename')
os.path.is_file()
檢查data_file
是否實際上是一個檔案。 如果是,則通過呼叫os.remove()
刪除它。 如果data_file
指向資料夾,則會向控制檯輸出錯誤訊息。
以下示例說明如何在刪除檔案時使用異常處理來處理錯誤:
import os
data_file = 'home/data.txt'
# 使用異常處理
try:
os.remove(data_file)
except OSError as e:
print(f'Error: {data_file} : {e.strerror}')
上面的程式碼嘗試在檢查其型別之前先刪除該檔案。 如果data_file
實際上不是檔案,則丟擲的OSError
將在except子句中處理,並向控制檯輸出錯誤訊息。 打印出的錯誤訊息使用Python f-strings格式化。
最後,你還可以使用pathlib.Path.unlink()
刪除檔案:
from pathlib import Path
data_file = Path('home/data.txt')
try:
data_file.unlink()
except IsADirectoryError as e:
print(f'Error: {data_file} : {e.strerror}')
這將建立一個名為data_file
的Path
物件,該物件指向一個檔案。 在data_file
上呼叫.unlink()將刪除home / data.txt
。 如果data_file
指向目錄,則引發IsADirectoryError
。 值得注意的是,上面的Python程式和執行它的使用者具有相同的許可權。 如果使用者沒有刪除檔案的許可權,則會引發PermissionError
。
刪除目錄
標準庫提供了一下函式來刪除目錄:
- os.rmdir()
- pathlib.Path.rmdir()
- shutil.rmtree()
要刪除單個目錄或資料夾可以使用os.rmdir()
或pathlib.Path.rmdir()
。這兩個函式只在你刪除空目錄的時候有效。如果目錄不為空,則會丟擲OSError
。下面演示如何刪除一個資料夾:
import os
trash_dir = 'my_documents/bad_dir'
try:
os.rmdir(trash_dir)
except OSError as e:
print(f'Error: {trash_dir} : {e.strerror}')
現在,trash_dir
已經通過os.rmdir()
被刪除了。如果目錄不為空,則會在螢幕上列印錯誤資訊:
Traceback (most recent call last):
File '<stdin>', line 1, in <module>
OSError: [Errno 39] Directory not empty: 'my_documents/bad_dir'
同樣,你也可使用pathlib
來刪除目錄:
from pathlib import Path
trash_dir = Path('my_documents/bad_dir')
try:
trash_dir.rmdir()
except OSError as e:
print(f'Error: {trash_dir} : {e.strerror}')
這裡建立了一個Path
物件指向要被刪除的目錄。如果目錄為空,呼叫Path
物件的.rmdir()
方法刪除它。
刪除完整的目錄樹
要刪除非空目錄和完整的目錄樹,Python提供了shutil.rmtree()
:
import shutil
trash_dir = 'my_documents/bad_dir'
try:
shutil.rmtree(trash_dir)
except OSError as e:
print(f'Error: {trash_dir} : {e.strerror}')
當呼叫shutil.rmtree()
時,trash_dir
中的所有內容都將被刪除。 在某些情況下,你可能希望以遞迴方式刪除空資料夾。 你可以使用上面討論的方法之一結合os.walk()
來完成此操作:
import os
for dirpath, dirnames, files in os.walk('.', topdown=False):
try:
os.rmdir(dirpath)
except OSError as ex:
pass
這將遍歷目錄樹並嘗試刪除它找到的每個目錄。 如果目錄不為空,則引發OSError並跳過該目錄。 下表列出了本節中涉及的功能:
| 函式 | 描述 | | --------------------- | ------------------------------------ | | os.remove() | 刪除單個檔案,不能刪除目錄 | | os.unlink() | 和os.remove()一樣,職能刪除單個檔案 | | pathlib.Path.unlink() | 刪除單個檔案,不能刪除目錄 | | os.rmdir() | 刪除一個空目錄 | | pathlib.Path.rmdir() | 刪除一個空目錄 | | shutil.rmtree() | 刪除完整的目錄樹,可用於刪除非空目錄 |
複製、移動和重新命名檔案和目錄
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()
與基於UNIX的系統中的cp
命令相當。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)
使用.copy2()
保留有關檔案的詳細資訊,例如上次訪問時間,許可權位,上次修改時間和標誌。
複製目錄
雖然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')
要使用pathlib
重新命名檔案,首先要建立一個pathlib.Path()
物件,該物件包含要替換的檔案的路徑。 下一步是在路徑物件上呼叫rename()
並傳入你要重新命名的檔案或目錄的新名稱。
歸檔
歸檔是將多個檔案打包成一個檔案的便捷方式。 兩種最常見的存檔型別是ZIP和TAR。 你編寫的Python程式可以建立存檔檔案,讀取存檔檔案和從存檔檔案中提取資料。 你將在本節中學習如何讀取和寫入兩種壓縮格式。
讀取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個子目錄:
.
|
├── sub_dir/
| ├── bar.py
| └── foo.py
|
├── file1.py
├── file2.py
└── file3.py
要獲取存檔檔案中的檔案列表,請在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)
這將輸出:
15277
.getinfo()
返回一個ZipInfo
物件,該物件儲存有關存檔檔案的單個成員的資訊。 要獲取有關存檔檔案中檔案的資訊,請將其路徑作為引數傳遞給.getinfo()
。 使用getinfo()
,你可以檢索有關存檔檔案成員的資訊,例如上次修改檔案的日期,壓縮大小及其完整檔名。 訪問.file_size
將以位元組為單位檢索檔案的原始大小。
以下示例說明如何在Python REPL中檢索有關已歸檔檔案的更多詳細資訊。 假設已匯入zipfile
模組,bar_info
與在前面的示例中建立的物件相同:
>>> bar_info.date_time
(2018, 10, 7, 23, 30, 10)
>>> bar_info.compress_size
2856
>>> bar_info.filename
'sub_dir/bar.py'
bar_info
包含有關bar.py
的詳細資訊,例如壓縮的大小及其完整路徑。
第一行顯示瞭如何檢索檔案的上次修改日期。 下一行顯示瞭如何在歸檔後獲取檔案的大小。 最後一行顯示了存檔檔案中bar.py
的完整路徑。
ZipFile
支援上下文管理器協議,這就是你可以將它與with語句一起使用的原因。 操作完成後會自動關閉ZipFile
物件。 嘗試從已關閉的ZipFile
物件中開啟或提取檔案將導致錯誤。
提取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語句,在完成提取後,存檔檔案會自動關閉。
建立新的存檔檔案
要建立新的ZIP存檔,請以寫入模式(w)開啟ZipFile
物件並新增要歸檔的檔案:
>>> import zipfile
>>> file_list = ['file1.py', 'sub_dir/', 'sub_dir/bar.py', 'sub_dir/foo.py']
>>> with zipfile.ZipFile('new.zip', 'w') as new_zip:
... for name in file_list:
... new_zip.write(name)
在該示例中,new_zip
以寫入模式開啟,file_list
中的每個檔案都新增到存檔檔案中。 with語句結束後,將關閉new_zip
。 以寫入模式開啟ZIP檔案會刪除壓縮檔案的內容並建立新存檔檔案。
要將檔案新增到現有的存檔檔案,請以追加模式開啟ZipFile
物件,然後新增檔案:
>>> with zipfile.ZipFile('new.zip', 'a') as new_zip:
... new_zip.write('data.txt')
... new_zip.write('latin.txt')
這裡開啟在上一個示例中以追加模式建立的new.zip
存檔。 在追加模式下開啟ZipFile
物件允許將新檔案新增到ZIP檔案而不刪除其當前內容。 將檔案新增到ZIP檔案後,with語句將脫離上下文並關閉ZIP檔案。
開啟TAR存檔檔案
TAR檔案是像ZIP等未壓縮的檔案存檔。 它們可以使用gzip
,bzip2
和lzma
壓縮方法進行壓縮。TarFile
類允許讀取和寫入TAR存檔。
下面是從存檔中讀取:
import tarfile
with tarfile.open('example.tar', 'r') as tar_file:
print(tar_file.getnames())
tarfile
物件像大多數類似檔案的物件一樣開啟。 它們有一個open()
函式,它採用一種模式來確定檔案的開啟方式。
使用“r”,“w”或“a”模式分別開啟未壓縮的TAR檔案以進行讀取,寫入和追加。 要開啟壓縮的TAR檔案,請將模式引數傳遞給tarfile.open()
,其格式為filemode [:compression]
。 下表列出了可以開啟TAR檔案的可能模式:
| 模式 | 行為 | | ----- | ----------------------------- | | r | 以無壓縮的讀取模式開啟存檔 | | r:gz | 以gzip壓縮的讀取模式開啟存檔 | | r:bz2 | 以bzip2壓縮的讀取模式開啟存檔 | | w | 以無壓縮的寫入模式開啟存檔 | | w:gz | 以gzip壓縮的寫入模式開啟存檔 | | w:xz | 以lzma壓縮的寫入模式開啟存檔 | | a | 以無壓縮的追加模式開啟存檔 |
.open()
預設為'r'模式。 要讀取未壓縮的TAR檔案並檢索其中的檔名,請使用.getnames()
:
>>> import tarfile
>>> tar = tarfile.open('example.tar', mode='r')
>>> tar.getnames()
['CONTRIBUTING.rst', 'README.md', 'app.py']
這以列表的方式返回存檔中內容的名字。
注意:為了向你展示如何使用不同的tarfile物件方法,示例中的TAR檔案在互動式REPL會話中手動開啟和關閉。
通過這種方式與TAR檔案互動,你可以檢視執行每個命令的輸出。 通常,你可能希望使用上下文管理器來開啟類似檔案的物件。
此外可以使用特殊屬性訪問存檔中每個條目的元資料:
>>> for entry in tar.getmembers():
... print(entry.name)
... print(' Modified:', time.ctime(entry.mtime))
... print(' Size :', entry.size, 'bytes')
... print()
CONTRIBUTING.rst
Modified: Sat Nov 1 09:09:51 2018
Size : 402 bytes
README.md
Modified: Sat Nov 3 07:29:40 2018
Size : 5426 bytes
app.py
Modified: Sat Nov 3 07:29:13 2018
Size : 6218 bytes
在此示例中,迴圈遍歷.getmembers()
返回的檔案列表,並打印出每個檔案的屬性。.getmembers()
返回的物件具有可以通過程式設計方式訪問的屬性,例如歸檔中每個檔案的名稱,大小和上次修改時間。 在讀取或寫入存檔後,必須關閉它以釋放系統資源。
從TAR存檔中提取檔案
在本節中,你將學習如何使用以下方法從TAR存檔中提取檔案:
.extract()
.extractfile()
.extractall()
要從TAR存檔中提取單個檔案,請使用extract()
,傳入檔名:
>>> tar.extract('README.md')
>>> os.listdir('.')
['README.md', 'example.tar']
README.md
檔案從存檔中提取到檔案系統。 呼叫os.listdir()
確認README.md
檔案已成功提取到當前目錄中。 要從存檔中解壓縮或提取所有內容,請使用.extractall()
:
>>> tar.extractall(path="extracted/")
.extractall()
有一個可選的path
引數來指定解壓縮檔案的去向。 這裡,存檔被提取到extracted
目錄中。 以下命令顯示已成功提取存檔:
$ ls
example.tar extracted README.md
$ tree
.
├── example.tar
├── extracted
| ├── app.py
| ├── CONTRIBUTING.rst
| └── README.md
└── README.md
1 directory, 5 files
$ ls extracted/
app.py CONTRIBUTING.rst README.md
要提取檔案物件以進行讀取或寫入,請使用.extractfile()
,它接收 檔名或TarInfo
物件作為引數。.extractfile()
返回一個可以讀取和使用的類檔案物件:
>>> f = tar.extractfile('app.py')
>>> f.read()
>>> tar.close()
開啟的存檔應在讀取或寫入後始終關閉。 要關閉存檔,請在存檔檔案控制代碼上呼叫.close()
,或在建立tarfile
物件時使用with語句,以便在完成後自動關閉存檔。 這將釋放系統資源,並將你對存檔所做的任何更改寫入檔案系統。
建立新的TAR存檔
建立新的TAR存檔,你可以這樣操作:
>>> import tarfile
>>> file_list = ['app.py', 'config.py', 'CONTRIBUTORS.md', 'tests.py']
>>> with tarfile.open('packages.tar', mode='w') as tar:
... for file in file_list:
... tar.add(file)
>>> # Read the contents of the newly created archive
>>> with tarfile.open('package.tar', mode='r') as t:
... for member in t.getmembers():
... print(member.name)
app.py
config.py
CONTRIBUTORS.md
tests.py
首先,你要建立要新增到存檔的檔案列表,這樣你就不必手動新增每個檔案。
下一行使用with光線文管理器在寫入模式下開啟名為packages.tar
的新存檔。 以寫入模式('w')開啟存檔使你可以將新檔案寫入存檔。 將刪除存檔中的所有現有檔案,並建立新存檔。
建立並填充存檔後,with上下文管理器會自動關閉它並將其儲存到檔案系統。 最後三行開啟剛剛建立的存檔,並打印出其中包含的檔案的名稱。
要將新檔案新增到現有存檔,請以追加模式('a')開啟存檔:
>>> with tarfile.open('package.tar', mode='a') as tar:
... tar.add('foo.bar')
>>> with tarfile.open('package.tar', mode='r') as tar:
... for member in tar.getmembers():
... print(member.name)
app.py
config.py
CONTRIBUTORS.md
tests.py
foo.bar
在追加模式下開啟存檔允許你向其新增新檔案而不刪除其中已存在的檔案。
使用壓縮存檔
tarfile
可以讀取和寫入使用gzip
,bzip2
和lzma
壓縮的TAR存檔檔案。 要讀取或寫入壓縮存檔,請使用tarfile.open()
,為壓縮型別傳遞適當的模式。
例如,要讀取或寫入使用gzip
壓縮的TAR存檔的資料,請分別使用'r:gz'
或'w:gz'
模式:
>>> files = ['app.py', 'config.py', 'tests.py']
>>> with tarfile.open('packages.tar.gz', mode='w:gz') as tar:
... tar.add('app.py')
... tar.add('config.py')
... tar.add('tests.py')
>>> with tarfile.open('packages.tar.gz', mode='r:gz') as t:
... for member in t.getmembers():
... print(member.name)
app.py
config.py
tests.py
'w:gz'
以寫模式模式開啟gzip
壓縮的存檔,'r:gz'
以讀模式開啟gzip
壓縮的存檔。 無法在追加模式下開啟壓縮存檔。 要將檔案新增到壓縮存檔,你必須建立新存檔。
一個更簡單的方式建立存檔
Python標準庫還支援使用shutil
模組中的高階方法建立TAR和ZIP存檔。shutil
中的歸檔實用工具允許你建立,讀取和提取ZIP和TAR歸檔。 這些實用工具依賴於較底層的tarfile
和zipfile
模組。
使用shutil.make_archive()建立存檔
shutil.make_archive()
至少接收兩個引數:歸檔的名稱和歸檔格式。
預設情況下,它將當前目錄中的所有檔案壓縮為format
引數中指定的歸檔格式。 你可以傳入可選的root_dir
引數來壓縮不同目錄中的檔案。.make_archive()
支援zip
,tar
,bztar
和gztar
存檔格式。
以下是使用shutil
建立TAR存檔的方法:
import shutil
# shutil.make_archive(base_name, format, root_dir)
shutil.make_archive('data/backup', 'tar', 'data/')
這將複製data /
中的所有內容,並在檔案系統中建立名為backup.tar
的存檔並返回其名稱。 要提取存檔,請呼叫.unpack_archive()
:
shutil.unpack_archive('backup.tar', 'extract_dir/')
呼叫.unpack_archive()
並傳入存檔名稱和目標目錄,將backup.tar
的內容提取到extract_dir/
中。 ZIP存檔可以以相同的方式建立和提取。
讀取多個檔案
Python支援通過fileinput
模組從多個輸入流或檔案列表中讀取資料。 此模組允許你快速輕鬆地迴圈遍歷一個或多個文字檔案的內容。 以下是使用fileinput
的典型方法:
import fileinput
for line in fileinput.input()
process(line)
fileinput
預設從傳遞給sys.argv
的命令列引數獲取其輸入。
使用fileinput迴圈遍歷多個檔案
讓我們使用fileinput
構建一個普通的UNIX工具cat
的原始版本。cat
工具按順序讀取檔案,將它們寫入標準輸出。 當在命令列引數中給出多個檔案時,cat
將連線文字檔案並在終端中顯示結果:
# File: fileinput-example.py
import fileinput
import sys
files = fileinput.input()
for line in files:
if fileinput.isfirstline():
print(f'\n--- Reading {fileinput.filename()} ---')
print(' -> ' + line, end='')
print()
在當前目錄中有兩個文字檔案,執行此命令會產生以下輸出:
$ python3 fileinput-example.py bacon.txt cupcake.txt
--- Reading bacon.txt ---
-> Spicy jalapeno bacon ipsum dolor amet in in aute est qui enim aliquip,
-> irure cillum drumstick elit.
-> Doner jowl shank ea exercitation landjaeger incididunt ut porchetta.
-> Tenderloin bacon aliquip cupidatat chicken chuck quis anim et swine.
-> Tri-tip doner kevin cillum ham veniam cow hamburger.
-> Turkey pork loin cupidatat filet mignon capicola brisket cupim ad in.
-> Ball tip dolor do magna laboris nisi pancetta nostrud doner.
--- Reading cupcake.txt ---
-> Cupcake ipsum dolor sit amet candy I love cheesecake fruitcake.
-> Topping muffin cotton candy.
-> Gummies macaroon jujubes jelly beans marzipan.
fileinput
允許你檢索有關每一行的更多資訊,例如它是否是第一行(.isfirstline()),行號(.lineno())和檔名(.filename())。 你可以在這裡讀更多關於它的內容。
總結
你現在知道如何使用Python對檔案和檔案組執行最常見的操作。 你已經瞭解使用不同的內建模組來讀取,查詢和操作檔案。
你現在可以用Python來實現:
- 獲取目錄內容和檔案屬性
- 建立目錄和目錄樹
- 使用匹配模式匹配檔名
- 建立臨時檔案和目錄
- 移動,重新命名,複製和刪除檔案或目錄
- 從不同型別的存檔檔案中讀取和提取資料
- 使用fileinput同時讀取多個檔案