本文爲譯文,原文連接 working-with-files-in-pythonphp
Python中有幾個內置模塊和方法來處理文件。這些方法被分割到例如os
, os.path
, shutil
和 pathlib
等等幾個模塊中。文章將列舉Python中對文件最經常使用的操做和方法。html
在這篇文章中,你將學習如何:python
fileinput
模塊打開多個文件使用Python對文件進行讀和寫是十分簡單的。爲此,你首先必須使用合適的模式打開文件。這裏有一個如何打開文本文件並讀取其內容的例子。linux
with open('data.txt', 'r') as f:
data = f.read()
print('context: {}'.format(data))
複製代碼
open()
接收一個文件名和一個模式做爲它的參數,r
表示以只讀模式打開文件。想要往文件中寫數據的話,則用w
做爲參數。shell
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 獲取更多關於如何讀寫文件的信息。express
假設你當前的工做目錄有一個叫 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()
則是首選的方法。api
import os
entries = os.listdir('my_directory')
複製代碼
os.listdir()
返回一個Python列表,其中包含path參數所指目錄的文件和子目錄的名稱。bash
['file1.py', 'file2.csv', 'file3.txt', 'sub_dir', 'sub_dir_b', 'sub_dir_c']
複製代碼
目錄列表如今看上去不容易閱讀,對 os.listdir()
的調用結果使用循環打印有助於查看。app
for entry in entries:
print(entry)
""" file1.py file2.csv file3.txt sub_dir sub_dir_b sub_dir_c """
複製代碼
在現代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
複製代碼
將日期和時間轉換爲字符串的語法可能會讓你感到混亂。若是要了解更多的信息,請查詢相關的官方文檔 。另外一個方式則是閱讀 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()
默認是從上到下遍歷目錄:
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
模塊中的方法刪除單個文件,目錄和整個目錄樹。 如下將介紹如何刪除你再也不須要的文件和目錄。
要刪除單個文件,請使用 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()
。這兩個函數只在你刪除空目錄的時候有效。若是目錄不爲空,則會拋出 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程序能夠建立存檔文件,讀取存檔文件和從存檔文件中提取數據。 你將在本節中學習如何讀取和寫入兩種壓縮格式。
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
對象中打開或提取文件將致使錯誤。
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文件是像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存檔中提取文件:
.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存檔,你能夠這樣操做:
>>> 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()
至少接收兩個參數:歸檔的名稱和歸檔格式。
默認狀況下,它將當前目錄中的全部文件壓縮爲 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
構建一個普通的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來實現:
關注公衆號 <代碼與藝術>,學習更多國外精品技術文章。