shutil --- 高階文件操作?

源代碼: Lib/shutil.py


shutil 模塊提供了一系列對文件和文件集合的高階操作。 特別是提供了一些支持文件拷貝和刪除的函數。 對于單個文件的操作,請參閱 os 模塊。

警告

即便是高階文件拷貝函數 (shutil.copy(), shutil.copy2()) 也無法拷貝所有的文件元數據。

在 POSIX 平臺上,這意味著將丟失文件所有者和組以及 ACL 數據。 在 Mac OS 上,資源鉤子和其他元數據不被使用。 這意味著將丟失這些資源并且文件類型和創建者代碼將不正確。 在 Windows 上,將不會拷貝文件所有者、ACL 和替代數據流。

目錄和文件操作?

shutil.copyfileobj(fsrc, fdst[, length])?

將文件類對象 fsrc 的內容拷貝到文件類對象 fdst。 整數值 length 如果給出則為緩沖區大小。 特別地, length 為負值表示拷貝數據時不對源數據進行分塊循環處理;默認情況下會分塊讀取數據以避免不受控制的內存消耗。 請注意如果 fsrc 對象的當前文件位置不為 0,則只有從當前文件位置到文件末尾的內容會被拷貝。

shutil.copyfile(src, dst, *, follow_symlinks=True)?

src 文件的內容(不含元數據)拷貝到 dst 文件并返回 dst。 srcdst 是字符串形式的路徑。 dst 必須是完整的目標文件名;對于接受一個目標目錄路徑的拷貝請參見 shutil.copy()。 如果 srcdst 指定了同一文件,則將引發 SameFileError

目標位置必須是可寫的;否則將引發 OSError 異常。 如果 dst 已經存在,它將被替換。 特殊文件如字符或塊設備以及管道無法用此函數來拷貝。

如果 follow_symlinks 為假值且 src 為符號鏈接,則將創建一個新的符號鏈接而不是拷貝 src 所指向的文件。

在 3.3 版更改: 曾經是引發 IOError 而不是 OSError。 增加了 follow_symlinks 參數。 現在是返回 dst

在 3.4 版更改: 引發 SameFileError 而不是 Error。 由于前者是后者的子類,此改變是向后兼容的。

exception shutil.SameFileError?

此異常會在 copyfile() 中的源和目標為同一文件時被引發。

3.4 新版功能.

shutil.copymode(src, dst, *, follow_symlinks=True)?

src 拷貝權限位到 dst。 文件的內容、所有者和分組將不受影響。 srcdst 均為字符串形式的路徑名。 如果 follow_symlinks 為假值,并且 srcdst 均為符號鏈接,copymode() 將嘗試修改 dst 本身的模式(而非它所指向的文件)。 此功能并不是在所有平臺上均可用;請參閱 copystat() 了解詳情。 如果 copymode() 無法修改本機平臺上的符號鏈接,而它被要求這樣做,它將不做任何操作即返回。

在 3.3 版更改: 加入 follow_symlinks 參數。

shutil.copystat(src, dst, *, follow_symlinks=True)?

src 拷貝權限位、最近訪問時間、最近修改時間以及旗標到 dst。 在 Linux 上,copystat() 還會在可能的情況下拷貝“擴展屬性”。 文件內容、所有者和分組將不受影響。 srcdst 均為字符串形式的路徑名。

如果 follow_symlinks 為假值,并且 srcdst 均指向符號鏈接,copystat() 將作用于符號鏈接本身而非該符號鏈接所指向的文件 — 從 src 符號鏈接讀取信息,并將信息寫入 dst 符號鏈接。

注解

并非所有平臺者提供檢查和修改符號鏈接的功能。 Python 本身可以告訴你哪些功能是在本機上可用的。

  • 如果 os.chmod in os.supports_follow_symlinksTrue,則 copystat() 可以修改符號鏈接的權限位。

  • 如果 os.utime in os.supports_follow_symlinksTrue,則 copystat() 可以修改符號鏈接的最近訪問和修改時間。

  • 如果 os.chflags in os.supports_follow_symlinksTrue,則 copystat() 可以修改符號鏈接的旗標。 (os.chflags 不是在所有平臺上均可用。)

在此功能部分或全部不可用的平臺上,當被要求修改一個符號鏈接時,copystat() 將盡量拷貝所有內容。 copystat() 一定不會返回失敗信息。

更多信息請參閱 os.supports_follow_symlinks

在 3.3 版更改: 添加了 follow_symlinks 參數并且支持 Linux 擴展屬性。

shutil.copy(src, dst, *, follow_symlinks=True)?

將文件 src 拷貝到文件或目錄 dst。 srcdst 應為字符串。 如果 dst 指定了一個目錄,文件將使用 src 中的基準文件名拷貝到 dst。 返回新創建文件所對應的路徑。

如果 follow_symlinks 為假值且 src 為符號鏈接,則 dst 也將被創建為符號鏈接。 如果 follow_symlinks 為真值且 src 為符號鏈接,dst 將成為 src 所指向的文件的一個副本。

copy() 會拷貝文件數據和文件的權限模式 (參見 os.chmod())。 其他元數據,例如文件的創建和修改時間不會被保留。 要保留所有原有的元數據,請改用 copy2() 。

在 3.3 版更改: 添加了 follow_symlinks 參數。 現在會返回新創建文件的路徑。

shutil.copy2(src, dst, *, follow_symlinks=True)?

類似于 copy(),區別在于 copy2() 還會嘗試保留文件的元數據。

follow_symlinks 為假值且 src 為符號鏈接時,copy2() 會嘗試將來自 src 符號鏈接的所有元數據拷貝到新創建的 dst 符號鏈接。 但是,此功能不是在所有平臺上均可用。 在此功能部分或全部不可用的平臺上,copy2() 將盡量保留所有元數據;copy2() 一定不會返回失敗的結果。

copy2() 會使用 copystat() 來拷貝文件元數據。 請參閱 copystat() 了解有關修改符號鏈接元數據的平臺支持的更多信息。

在 3.3 版更改: 添加了 follow_symlinks 參數,還會嘗試拷貝擴展文件系統屬性(目前僅限 Linux)。 現在會返回新創建文件的路徑。

shutil.ignore_patterns(*patterns)?

這個工廠函數會創建一個函數,它可被用作 copytree()ignore 可調用對象參數,以忽略那些匹配所提供的 glob 風格的 patterns 之一的文件和目錄。 參見以下示例。

shutil.copytree(src, dst, symlinks=False, ignore=None, copy_function=copy2, ignore_dangling_symlinks=False)?

遞歸地拷貝以 src 為根路徑的整個目錄樹,返回目標目錄。 名為 dst 的目標目錄不必已存在;它本身和還不存在的父目錄都將被自動創建。 目錄的權限和時間信息將通過 copystat() 來拷貝,單獨的文件將使用 shutil.copy2() 來拷貝。

如果 symlinks 為真值,源目錄樹中的符號鏈接會在新目錄樹中表示為符號鏈接,并且原鏈接的元數據在平臺允許的情況下也會被拷貝;如果為假值或省略,則會將被鏈接文件的內容和元數據拷貝到新目錄樹。

symlinks 為假值時,如果符號鏈接所指向的文件不存在,則會在拷貝進程的末尾將一個異常添加到 Error 異常中的錯誤列表。 如果你希望屏蔽此異常那就將可選的 ignore_dangling_symlinks 旗標設為真值。 請注意此選項在不支持 os.symlink() 的平臺上將不起作用。

如果給出了 ignore,它必須是一個可調用對象,該對象將接受 copytree() 所訪問的目錄以及 os.listdir() 所返回的目錄內容列表作為其參數。 由于 copytree() 是遞歸地被調用的,ignore 可調用對象對于每個被拷貝目錄都將被調用一次。 該可調用對象必須返回一個相對于當前目錄的目錄和文件名序列(即其第二個參數的子集);隨后這些名稱將在拷貝進程中被忽略。 ignore_patterns() 可被用于創建這種基于 glob 風格模式來忽略特定名稱的可調用對象。

如果發生了異常,將引發一個附帶原因列表的 Error。

如果給出了 copy_function,它必須是一個將被用來拷貝每個文件的可調用對象。 它在被調用時會將源路徑和目標路徑作為參數傳入。 默認情況下,shutil.copy2() 將被使用,但任何支持同樣簽名(與 shutil.copy() 一致)的函數都可以使用。

在 3.3 版更改: symlinks 為假值時拷貝元數據。 現在會返回 dst。

在 3.2 版更改: 添加了 copy_function 參數以允許提供定制的拷貝函數。 添加了 ignore_dangling_symlinks 參數以便在 symlinks 為假值時屏蔽符號鏈接錯誤。

shutil.rmtree(path, ignore_errors=False, onerror=None)?

刪除一個完整的目錄樹;path 必須指向一個目錄(但不能是一個目錄的符號鏈接)。 如果 ignore_errors 為真值,刪除失敗導致的錯誤將被忽略;如果為假值或是省略,此類錯誤將通過調用由 onerror 所指定的處理程序來處理,或者如果此參數被省略則將引發一個異常。

注解

在支持必要的基于 fd 的函數的平臺上,默認會使用 rmtree() 的可防御符號鏈接攻擊的版本。 在其他平臺上,rmtree() 較易遭受符號鏈接攻擊:給定適當的時間和環境,攻擊者可以操縱文件系統中的符號鏈接來刪除他們在其他情況下無法訪問的文件。 應用程序可以使用 rmtree.avoids_symlink_attacks 函數屬性來確定此類情況具體是哪一些。

如果提供了 onerror,它必須為接受三個形參的可調用對象: function, pathexcinfo

第一個形參 function 是引發異常的函數;它依賴于具體的平臺和實現。 第二個形參 path 將是傳遞給 function 的路徑名。 第三個形參 excinfo 將是由 sys.exc_info() 所返回的異常信息。 由 onerror 所引發的異常將不會被捕獲。

在 3.3 版更改: 添加了一個防御符號鏈接攻擊的版本,如果平臺支持基于 fd 的函數就會被使用。

指明當前平臺和實現是否提供防御符號鏈接攻擊的 rmtree() 版本。 目前它僅在平臺支持基于 fd 的目錄訪問函數時才返回真值。

3.3 新版功能.

shutil.move(src, dst, copy_function=copy2)?

遞歸地將一個文件或目錄 (src) 移至另一位置 (dst) 并返回目標位置。

如果目標是已存在的目錄,則 src 會被移至該目錄下。 如果目標已存在但不是目錄,它可能會被覆蓋,具體取決于 os.rename() 的語義。

如果目標是在當前文件系統中,則會使用 os.rename()。 在其他情況下,src 將被拷貝至 dst,使用的函數為 copy_function,然后目標會被移除。 對于符號鏈接,則將在 dst 之下或以其本身為名稱創建一個指向 src 目標的新符號鏈接,并且 src 將被移除。

如果給出了 copy_function,則它必須為接受兩個參數 srcdst 的可調用對象,并會在 os.rename() 無法使用時被用來將 src 拷貝到 dest。 如果源位置是一個目錄,則會調用 copytree(),并向它傳入 copy_function()。 默認的 copy_functioncopy2()。 使用 copy() 作為 copy_function 允許在無法附帶拷貝元數據時讓移動操作成功執行,但其代價是不拷貝任何元數據。

在 3.3 版更改: 為異類文件系統添加了顯式的符號鏈接處理,以便使它適應 GNU 的 mv 的行為。 現在會返回 dst。

在 3.5 版更改: 增加了 copy_function 關鍵字參數。

shutil.disk_usage(path)?

返回給定路徑的磁盤使用統計數據,形式為一個 named tuple,其中包含 total, usedfree 屬性,分別表示總計、已使用和未使用空間的字節數。 在 Windows 上,path 必須是一個目錄;在 Unix 上,它可以是一個文件或一個目錄。

3.3 新版功能.

可用性: Unix, Windows。

shutil.chown(path, user=None, group=None)?

修改給定 path 的所有者 user 和/或 group。

user 可以是一個系統用戶名或 uid;group 同樣如此。 要求至少有一個參數。

另請參閱下層的函數 os.chown()。

可用性: Unix。

3.3 新版功能.

shutil.which(cmd, mode=os.F_OK | os.X_OK, path=None)?

返回當給定的 cmd 被調用時將要運行的可執行文件的路徑。 如果沒有 cmd 會被調用則返回 None

mode 是一個傳遞給 os.access() 的權限掩碼,在默認情況下將確定文件是否存在并且為可執行文件。

當未指定 path 時,將會使用 os.environ() 的結果,返回 "PATH" 的值或回退為 os.defpath

在 Windows 上當前目錄總是會被添加為 path 的第一項,無論你是否使用默認值或提供你自己的路徑,這是命令行終端在查找可執行文件時所采用的行為方式。 此外,當在 path 中查找 cmd 時,還會檢查 PATHEXT 環境變量。 例如,如果你調用 shutil.which("python")which() 將搜索 PATHEXT 來確定它要在 path 目錄中查找 python.exe。 例如,在 Windows 上:

>>> shutil.which("python")
'C:\\Python33\\python.EXE'

3.3 新版功能.

exception shutil.Error?

此異常會收集在多文件操作期間所引發的異常。 對于 copytree(),此異常參數將是一個由三元組 (srcname, dstname, exception) 構成的列表。

copytree 示例?

這個示例就是上面所描述的 copytree() 函數的實現,其中省略了文檔字符串。 它還展示了此模塊所提供的許多其他函數。

def copytree(src, dst, symlinks=False):
    names = os.listdir(src)
    os.makedirs(dst)
    errors = []
    for name in names:
        srcname = os.path.join(src, name)
        dstname = os.path.join(dst, name)
        try:
            if symlinks and os.path.islink(srcname):
                linkto = os.readlink(srcname)
                os.symlink(linkto, dstname)
            elif os.path.isdir(srcname):
                copytree(srcname, dstname, symlinks)
            else:
                copy2(srcname, dstname)
            # XXX What about devices, sockets etc.?
        except OSError as why:
            errors.append((srcname, dstname, str(why)))
        # catch the Error from the recursive copytree so that we can
        # continue with other files
        except Error as err:
            errors.extend(err.args[0])
    try:
        copystat(src, dst)
    except OSError as why:
        # can't copy file access times on Windows
        if why.winerror is None:
            errors.extend((src, dst, str(why)))
    if errors:
        raise Error(errors)

另一個使用 ignore_patterns() 輔助函數的例子:

from shutil import copytree, ignore_patterns

copytree(source, destination, ignore=ignore_patterns('*.pyc', 'tmp*'))

這將會拷貝除 .pyc 文件和以 tmp 打頭的文件或目錄以外的所有條目.

另一個使用 ignore 參數來添加記錄調用的例子:

from shutil import copytree
import logging

def _logpath(path, names):
    logging.info('Working in %s', path)
    return []   # nothing will be ignored

copytree(source, destination, ignore=_logpath)

rmtree 示例?

這個例子演示了如何在 Windows 上刪除一個目錄樹,其中部分文件設置了只讀屬性位。 它會使用 onerror 回調函數來清除只讀屬性位并再次嘗試刪除。 任何后續的失敗都將被傳播。

import os, stat
import shutil

def remove_readonly(func, path, _):
    "Clear the readonly bit and reattempt the removal"
    os.chmod(path, stat.S_IWRITE)
    func(path)

shutil.rmtree(directory, onerror=remove_readonly)

歸檔操作?

3.2 新版功能.

在 3.5 版更改: 添加了對 xztar 格式的支持。

本模塊也提供了用于創建和讀取壓縮和歸檔文件的高層級工具。 它們依賴于 zipfiletarfile 模塊。

shutil.make_archive(base_name, format[, root_dir[, base_dir[, verbose[, dry_run[, owner[, group[, logger]]]]]]])?

創建一個歸檔文件(例如 zip 或 tar)并返回其名稱。

base_name 是要創建的文件名稱,包括路徑,去除任何特定格式的擴展名。 format 是歸檔格式:為 "zip" (如果 zlib 模塊可用), "tar", "gztar" (如果 zlib 模塊可用), "bztar" (如果 bz2 模塊可用) 或 "xztar" (如果 lzma 模塊可用) 中的一個。

root_dir 是一個目錄,它將作為歸檔文件的根目錄,歸檔中的所有路徑都將是它的相對路徑;例如,我們通常會在創建歸檔之前用 chdir 命令切換到 root_dir。

base_dir 是我們要執行歸檔的起始目錄;也就是說 base_dir 將成為歸檔中所有文件和目錄共有的路徑前綴。 base_dir 必須相對于 root_dir 給出。 請參閱 使用 base_dir 的歸檔程序示例 了解如何同時使用 base_dirroot_dir。

root_dirbase_dir 默認均為當前目錄。

如果 dry_run 為真值,則不會創建歸檔文件,但將要被執行的操作會被記錄到 logger

ownergroup 將在創建 tar 歸檔文件時被使用。 默認會使用當前的所有者和分組。

logger 必須是一個兼容 PEP 282 的對象,通常為 logging.Logger 的實例。

verbose 參數已不再使用并進入棄用狀態。

shutil.get_archive_formats()?

返回支持的歸檔格式列表。 所返回序列中的每個元素為一個元組 (name, description)。

默認情況下 shutil 提供以下格式:

  • zip: ZIP 文件(如果 zlib 模塊可用)。

  • tar: 未壓縮的 tar 文件。

  • gztar: gzip 壓縮的 tar 文件(如果 zlib 模塊可用)。

  • bztar: bzip2 壓縮的 tar 文件(如果 bz2 模塊可用)。

  • xztar: xz 壓縮的 tar 文件(如果 lzma 模塊可用)。

你可以通過使用 register_archive_format() 注冊新的格式或為任何現有格式提供你自己的歸檔程序。

shutil.register_archive_format(name, function[, extra_args[, description]])?

name 格式注冊一個歸檔程序。

function 是將被用來解包歸檔文件的可調用對象。 該可調用對象將接收要創建文件的 base_name,再加上要歸檔內容的 base_dir (其默認值為 os.curdir)。 更多參數會被作為關鍵字參數傳入: owner, group, dry_runlogger (與向 make_archive() 傳入的參數一致)。

如果給出了 extra_args,則其應為一個 (name, value) 對的序列,將在歸檔器可調用對象被使用時作為附加的關鍵字參數。

descriptionget_archive_formats() 使用,它將返回歸檔器的列表。 默認值為一個空字符串。

shutil.unregister_archive_format(name)?

從支持的格式中移除歸檔格式 name

shutil.unpack_archive(filename[, extract_dir[, format]])?

解包一個歸檔文件。 filename 是歸檔文件的完整路徑。

extract_dir 是歸檔文件解包的目標目錄名稱。 如果未提供,則將使用當前工作目錄。

format 是歸檔格式:應為 "zip", "tar", "gztar", "bztar" 或 "xztar" 之一。 或者任何通過 register_unpack_format() 注冊的其他格式。 如果未提供,unpack_archive() 將使用歸檔文件的后綴來檢查是否注冊了對應于該后綴的解包器。 在未找到任何解包器的情況下,將引發 ValueError

在 3.7 版更改: 接受一個 path-like object 作為 filenameextract_dir

shutil.register_unpack_format(name, extensions, function[, extra_args[, description]])?

注冊一個解包格式。 name 為格式名稱而 extensions 為對應于該格式的擴展名列表,例如 Zip 文件的擴展名為 .zip。

function 是將被用來解包歸檔文件的可調用對象。 該可調用對象將接受歸檔文件的路徑,加上該歸檔文件要被解包的目標目錄。

如果提供了 extra_args,則其應為一個 (name, value) 元組的序列,將被作為關鍵字參數傳遞給該可調用對象。

可以提供 description 來描述該格式,它將被 get_unpack_formats() 返回。

shutil.unregister_unpack_format(name)?

撤銷注冊一個解包格式。 name 為格式的名稱。

shutil.get_unpack_formats()?

返回所有已注冊的解包格式列表。 所返回序列中的每個元素為一個元組 (name, extensions, description)。

默認情況下 shutil 提供以下格式:

  • zip: ZIP 文件(只有在相應模塊可用時才能解包壓縮文件)。

  • tar: 未壓縮的 tar 文件。

  • gztar: gzip 壓縮的 tar 文件(如果 zlib 模塊可用)。

  • bztar: bzip2 壓縮的 tar 文件(如果 bz2 模塊可用)。

  • xztar: xz 壓縮的 tar 文件(如果 lzma 模塊可用)。

你可以通過使用 register_unpack_format() 注冊新的格式或為任何現有格式提供你自己的解包器。

歸檔程序示例?

在這個示例中,我們創建了一個 gzip 壓縮的 tar 歸檔文件,其中包含用戶的 .ssh 目錄下的所有文件:

>>> from shutil import make_archive
>>> import os
>>> archive_name = os.path.expanduser(os.path.join('~', 'myarchive'))
>>> root_dir = os.path.expanduser(os.path.join('~', '.ssh'))
>>> make_archive(archive_name, 'gztar', root_dir)
'/Users/tarek/myarchive.tar.gz'

結果歸檔文件中包含有:

$ tar -tzvf /Users/tarek/myarchive.tar.gz
drwx------ tarek/staff       0 2010-02-01 16:23:40 ./
-rw-r--r-- tarek/staff     609 2008-06-09 13:26:54 ./authorized_keys
-rwxr-xr-x tarek/staff      65 2008-06-09 13:26:54 ./config
-rwx------ tarek/staff     668 2008-06-09 13:26:54 ./id_dsa
-rwxr-xr-x tarek/staff     609 2008-06-09 13:26:54 ./id_dsa.pub
-rw------- tarek/staff    1675 2008-06-09 13:26:54 ./id_rsa
-rw-r--r-- tarek/staff     397 2008-06-09 13:26:54 ./id_rsa.pub
-rw-r--r-- tarek/staff   37192 2010-02-06 18:23:10 ./known_hosts

使用 base_dir 的歸檔程序示例?

在這個例子中,與 上面的例子 類似,我們演示了如何使用 make_archive(),但這次是使用 base_dir。 我們現在具有如下的目錄結構:

$ tree tmp
tmp
└── root
    └── structure
        ├── content
            └── please_add.txt
        └── do_not_add.txt

在最終的歸檔中,應當會包括 please_add.txt,但不應當包括 do_not_add.txt。 因此我們使用以下代碼:

>>> from shutil import make_archive
>>> import os
>>> archive_name = os.path.expanduser(os.path.join('~', 'myarchive'))
>>> make_archive(
...     archive_name,
...     'tar',
...     root_dir='tmp/root',
...     base_dir='structure/content',
... )
'/Users/tarek/my_archive.tar'

列出結果歸檔中的文件我們將會得到:

$ python -m tarfile -l /Users/tarek/myarchive.tar
structure/content/
structure/content/please_add.txt

查詢輸出終端的尺寸?

shutil.get_terminal_size(fallback=(columns, lines))?

獲取終端窗口的尺寸。

對于兩個維度中的每一個,會分別檢查環境變量 COLUMNSLINES。 如果定義了這些變量并且其值為正整數,則將使用這些值。

如果未定義 COLUMNSLINES,這是通常的情況,則連接到 sys.__stdout__ 的終端將通過發起調用 os.get_terminal_size() 被查詢。

如果由于系統不支持查詢,或是由于我們未連接到某個終端而導致查詢終端尺寸不成功,則會使用在 fallback 形參中給出的值。 fallback 默認為 (80, 24),這是許多終端模擬器所使用的默認尺寸。

返回的值是一個 os.terminal_size 類型的具名元組。

另請參閱: The Single UNIX Specification, Version 2, Other Environment Variables.

3.3 新版功能.