shutil —高级文件操作

源代码: Lib/shutil.py


shutil模块对文件和文件集合提供了许多高级操作。特别是提供了支持文件复制和删除的Function。有关单个文件的操作,另请参见os模块。

Warning

即使是更高级别的文件复制Function(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 *。 * src dst *是 Classpath 对象或以字符串形式给出的路径名。
  • dst 必须是完整的目标文件名;查看copy()以获取接受目标目录路径的副本。如果 src dst *指定相同的文件,则引发SameFileError

目标位置必须是可写的;否则,将引发OSErrorexception。如果* dst *已经存在,它将被替换。无法使用此Function复制特殊文件,例如字符或块设备以及管道。

如果* follow_symlinks 为 false 且 src 为符号链接,则将创建一个新的符号链接,而不是复制 src *指向的文件。

用参数srcdst引发auditing event shutil.copyfile

在版本 3.3 中进行了更改:IOError曾经被提升,而不是OSError。添加了* follow_symlinks 参数。现在返回 dst *。

在版本 3.4 中更改:提高SameFileError而不是Error。由于前者是后者的子类,因此此更改是向后兼容的。

在版本 3.8 中更改:可以在内部使用特定于平台的快速复制 syscall,以便更有效地复制文件。请参阅平台相关的高效复制操作部分。

  • exception shutil. SameFileError
    • 如果copyfile()中的源和目标是同一文件,则会引发此异常。

3.4 版的新Function。

  • shutil. copymode(* src dst **,* follow_symlinks = True *)
    • 将权限位从* src 复制到 dst *。文件内容,所有者和组不受影响。 * src dst 是 Classpath 对象或以字符串形式给出的路径名。如果 follow_symlinks 为 false,并且 src dst 均为符号链接,则copymode()将try修改 dst *本身的模式(而不是其指向的文件)。并非在所有平台上都提供此Function。请参阅copystat()以获取更多信息。如果copymode()无法在本地平台上修改符号链接,并且要求这样做,它将什么都不做并返回。

用参数srcdst引发auditing event shutil.copymode

在版本 3.3 中更改:添加了* follow_symlinks *参数。

  • shutil. copystat(* src dst **,* follow_symlinks = True *)
    • 将权限位,上次访问时间,上次修改时间和标志从* src 复制到 dst *。在 Linux 上,copystat()还尽可能复制“扩展属性”。文件内容,所有者和组不受影响。 * src dst *是 Classpath 对象或以字符串形式给出的路径名。

如果* follow_symlinks 为 false,并且 src dst 都引用了符号链接,则copystat()将对符号链接本身进行操作,而不是对符号链接所引用的文件进行操作-从 src 符号链接中读取信息,并将信息写入 dst *符号链接。

Note

并非所有平台都提供检查和修改符号链接的Function。 Python 本身可以告诉您哪些Function在本地可用。

  • 如果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并非在所有平台上都可用.)

在某些或所有此Function不可用的平台上,当要求修改符号链接时,copystat()将复制所有可能的内容。 copystat()从不返回失败。

有关更多信息,请参见os.supports_follow_symlinks

用参数srcdst引发auditing event shutil.copystat

在版本 3.3 中进行了更改:添加了* follow_symlinks *参数并支持 Linux 扩展属性。

  • shutil. copy(* src dst **,* follow_symlinks = True *)
    • 将文件* src 复制到文件或目录 dst *。 * src dst 应该是字符串。如果 dst 指定目录,则文件将使用 src 中的基本文件名复制到 dst *中。返回新创建文件的路径。

如果* follow_symlinks 为 false,并且 src 为符号链接,则 dst 将被创建为符号链接。如果 follow_symlinks 为 true 且 src 为符号链接,则 dst 将为 src *所指文件的副本。

copy()复制文件数据和文件的许可模式(请参阅os.chmod())。不保留其他元数据,例如文件的创建和修改时间。要保留原始文件中的所有文件元数据,请改用copy2()

用参数srcdst引发auditing event shutil.copyfile

用参数srcdst引发auditing event shutil.copymode

在版本 3.3 中更改:添加了* follow_symlinks *参数。现在返回新创建文件的路径。

在版本 3.8 中更改:可以在内部使用特定于平台的快速复制 syscall,以便更有效地复制文件。请参阅平台相关的高效复制操作部分。

  • shutil. copy2(* src dst **,* follow_symlinks = True *)
    • copy()相同,除了copy2()还会try保留文件元数据。

当* follow_symlinks 为 false,并且 src 为符号链接时,copy2()try将所有元数据从 src 符号链接复制到新创建的 dst *符号链接。但是,此Function并非在所有平台上都可用。在某些或所有此Function不可用的平台上,copy2()将保留所有可以使用的元数据; copy2()永远不会引发异常,因为它无法保留文件元数据。

copy2()使用copystat()复制文件元数据。请参阅copystat(),以获取有关平台支持的更多信息,以支持修改符号链接元数据。

用参数srcdst引发auditing event shutil.copyfile

用参数srcdst引发auditing event shutil.copystat

在版本 3.3 中进行了更改:添加了* follow_symlinks *参数,也try复制扩展文件系统属性(当前仅适用于 Linux)。现在返回新创建文件的路径。

在版本 3.8 中更改:可以在内部使用特定于平台的快速复制 syscall,以便更有效地复制文件。请参阅平台相关的高效复制操作部分。

  • shutil. ignore_patterns(*模式)

    • 此工厂函数创建的函数可用作copytree()的* ignore 参数的可调用函数,而忽略与提供的 glob 样式 patterns *之一匹配的文件和目录。请参见下面的示例。
  • shutil. copytree(* src dst symlinks = False ignore = None copy_function = copy2 ignore_dangling_symlinks = False dirs_exist_ok = False *)

    • 将整个以* src 为根的目录树递归复制到名为 dst *的目录中,并返回目标目录。 * dirs_exist_ok 指示是否在 dst *或任何丢失的父目录已存在的情况下引发异常。

目录的权限和时间使用copystat()复制,单个文件使用copy2()复制。

如果* symlinks *为 true,则将源树中的符号链接表示为新树中的符号链接,并且将在平台允许的范围内复制原始链接的元数据。如果为 false 或Ellipsis,则将链接文件的内容和元数据复制到新树。

当* symlinks 为 false 时,如果符号链接指向的文件不存在,则在复制过程结束时,将在Error异常引发的错误列表中添加一个异常。如果要使此异常静音,可以将可选的 ignore_dangling_symlinks *标志设置为 true。请注意,此选项对不支持os.symlink()的平台无效。

如果给定* ignore ,则它必须是可调用的,它将接受copytree()访问的目录以及os.listdir()返回的目录列表作为其参数。由于copytree()是递归调用的,因此 ignore *可调用对象将为每个复制的目录调用一次。可调用对象必须返回相对于当前目录的一系列目录和文件名(即,其第二个参数中各项的子集);这些名称将在复制过程中被忽略。 ignore_patterns()可用于创建这样的可调用项,该可调用项将忽略基于全局样式的名称。

如果发生异常,则会引发Error并列出原因。

如果给出了* copy_function *,它必须是可调用的,将用于复制每个文件。将使用源路径和目标路径作为参数来调用它。默认情况下,使用copy2(),但是可以使用支持相同签名的任何函数(例如copy())。

用参数srcdst引发auditing event shutil.copytree

在版本 3.3 中进行了更改:* symlinks 为 false 时,复制元数据。现在返回 dst *。

在版本 3.2 中进行了更改:添加了* copy_function 参数,以便能够提供自定义复制Function。当 symlinks 为 false 时,将 ignore_dangling_symlinks *参数添加到无声悬挂符号链接错误中。

在版本 3.8 中更改:可以在内部使用特定于平台的快速复制 syscall,以便更有效地复制文件。请参阅平台相关的高效复制操作部分。

3.8 版的新Function:* dirs_exist_ok *参数。

  • shutil. rmtree(* path ignore_errors = False onerror = None *)
    • 删除整个目录树; * path 必须指向目录(但不能指向目录的符号链接)。如果 ignore_errors 为 true,则删除失败导致的错误将被忽略;如果为 false 或被忽略,则pass调用 onerror *指定的处理程序来处理此类错误;或者,如果忽略该错误,则会引发异常。

Note

在支持必要的基于 fd 的Function的平台上,默认情况下使用抗符号链接版本rmtree()。在其他平台上,rmtree()实现易受符号链接攻击:在适当的时机和环境下,攻击者可以操纵文件系统上的符号链接来删除原本无法访问的文件。应用程序可以使用rmtree.avoids_symlink_attacks函数属性来确定哪种情况适用。

如果提供了* onerror ,则它必须是可调用的,可以接受三个参数: function path excinfo *。

第一个参数* function 是引发异常的函数;这取决于平台和实现。第二个参数 path 将是传递给 function 的路径名。第三个参数 excinfo *将是sys.exc_info()返回的异常信息。 * onerror *引发的异常不会被捕获。

用参数path引发auditing event shutil.rmtree

在版本 3.3 中更改:添加了一个抗符号链接攻击的版本,如果平台支持基于 fd 的Function,该版本将自动使用。

在版本 3.8 中进行了更改:在 Windows 上,在删除联结之前将不再删除目录联结的内容。

版本 3.3 中的新Function。

  • shutil. move(* src dst copy_function = copy2 *)
    • 将文件或目录(* src )递归移动到另一个位置( dst *),然后返回目标位置。

如果目标是现有目录,则* src *将移动到该目录内。如果目标已经存在但不是目录,则可能会根据os.rename()的语义将其覆盖。

如果目标位于当前文件系统上,则使用os.rename()。否则,使用* copy_function src 复制到 dst ,然后将其删除。对于符号链接,将在 dst 中或以 dst 创建指向 src 目标的新符号链接,并删除 src *。

如果给出了* copy_function ,则它必须是带有两个参数 src dst 的可调用对象,如果无法使用os.rename(),它将用于将 src 复制到 dest 。如果源是目录,则会调用copytree()并将其传递给copy_function()。默认的 copy_function copy2()。在无法复制元数据的情况下,将copy()用作 copy_function *可以使移动成功,但要以不复制任何元数据为代价。

用参数srcdst引发auditing event shutil.move

在版本 3.3 中进行了更改:为外部文件系统添加了显式符号链接处理,从而使其适应 GNU mv 的行为。现在返回* dst *。

在版本 3.5 中进行了更改:添加了* copy_function *关键字参数。

在版本 3.8 中更改:可以在内部使用特定于平台的快速复制 syscall,以便更有效地复制文件。请参阅平台相关的高效复制操作部分。

  • shutil. disk_usage(* path *)
    • named tuple的形式返回有关给定路径的磁盘使用情况统计信息,其属性为* total used free *,它们是总的已用空间和可用空间(以字节为单位)。 * path *可以是文件或目录。

版本 3.3 中的新Function。

在版本 3.8 中更改:在 Windows 上,* path *现在可以是文件或目录。

Availability:Unix,Windows。

  • shutil. chown(* path user = None group = None *)
    • 更改给定* path 的所有者 user 和/或 group *。
  • user 可以是系统用户名或 uid;同样适用于 group *。至少需要一个参数。

另请参见os.chown()(基础Function)。

用参数pathusergroup引发auditing event shutil.chown

Availability: Unix.

版本 3.3 中的新Function。

  • 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 之前,这是命令 Shell 程序在查找可执行文件时使用的行为。另外,在 path 中找到 cmd 时,将检查PATHEXT环境变量。例如,如果您调用shutil.which("python"),则which()将搜索PATHEXT以知道它应在 path *目录中寻找python.exe。例如,在 Windows 上:

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

版本 3.3 中的新Function。

在 3.8 版中更改:现在接受bytes类型。如果* cmd *类型为bytes,则结果类型也是bytes

  • exception shutil. Error
    • 此异常收集在多文件操作期间引发的异常。对于copytree(),exception 参数是一个三 Tuples 的列表(* srcname dstname exception *)。

取决于平台的有效复制操作

从 Python 3.8 开始,涉及文件复制的所有函数(copyfile()copy()copy2()copytree()move())都可以使用特定于平台的“快速复制”系统调用来更有效地复制文件(请参见bpo-33671)。 “快速复制”是指复制操作在内核内进行,避免了像“ outfd.write(infd.read())”那样在 Python 中使用用户空间缓冲区。

在 macOS 上,fcopyfile用于复制文件内容(不是元数据)。

在 Linux 上使用os.sendfile()

在 Windows 上,shutil.copyfile()使用更大的默认缓冲区大小(1 MiB 而不是 64 KiB),并使用基于memoryview()shutil.copyfileobj()变体。

如果快速复制操作失败,并且没有在目标文件中写入任何数据,则 shutil 将在内部使用效率较低的copyfileobj()Function进行静默回退。

在 3.8 版中进行了更改。

copytree example

此示例是上述copytree()函数的实现,其中Ellipsis了文档字符串。它演示了此模块提供的许多其他Function。

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 example

本示例说明如何在 Windows 上删除目录树,其中某些文件的只读位已设置。它使用 onerror 回调清除只读位并重新try删除。任何后续故障都将传播。

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)

Archiving operations

3.2 版中的新Function。

在版本 3.5 中进行了更改:添加了对* xztar *格式的支持。

还提供了用于创建和读取压缩和存档文件的高级 Util。他们依靠zipfiletarfile模块。

  • shutil. make_archive(* base_name format * [,* root_dir * [,* base_dir * [,* verbose * [,* dry_run * [,* owner * [,* group * [,* logger *]]]]]] ]])
    • 创建一个存档文件(例如 zip 或 tar)并返回其名称。
  • base_name *是要创建的文件的名称,包括路径,减去任何特定于格式的 extensions。 * format *是存档格式:“ zip”(如果有zlib模块可用),“ tar”,“ gztar”(如果有zlib模块可用),“ bztar”(如果有bz2模块)之一,或“ xztar”(如果lzma模块可用)。

  • root_dir 是一个目录,它将是 Files 的根目录,Files 中的所有路径都是相对的;例如,我们通常在创建 Files 之前将 chdir 插入 root_dir *。

  • base_dir 是我们开始存档的目录;即 base_dir *将是 Files 中所有文件和目录的通用前缀。 * base_dir 必须相对于 root_dir 给出。有关如何一起使用 base_dir root_dir *的信息,请参见使用 base_dir 归档示例

  • root_dir base_dir *都默认为当前目录。

如果* dry_run 为 true,则不会创建任何存档,但是将要执行的操作记录到 logger *中。

创建 tar 归档文件时使用* owner group *。默认情况下,使用当前所有者和组。

  • logger *必须是与 PEP 282兼容的对象,通常是logging.Logger的实例。

  • verbose *参数未使用且已弃用。

用参数base_nameformatroot_dirbase_dir引发auditing event shutil.make_archive

在版本 3.8 中进行了更改:对于使用format="tar"创建的 Files,现在使用现代 pax(POSIX.1-2001)格式,而不是旧版 GNU 格式。

  • shutil. get_archive_formats ( )
    • 返回用于归档的受支持格式的列表。返回序列的每个元素都是 Tuples(name, description)

默认情况下,shutil提供以下格式:

    • zip *:ZIP 文件(如果zlib模块可用)。
    • tar *:未压缩的 tar 文件。对新 Files 使用 POSIX.1-2001 pax 格式。
    • 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 是将用于解压缩 Files 的可调用对象。可调用对象将接收要创建的文件的 base_name ,然后是 base_dir (默认为os.curdir)以开始归档。其他参数作为关键字参数传递: owner group dry_run logger *(在make_archive()中传递)。

如果给定,则* extra_args *是(name, value)对的序列,当使用 Archiver Callable 时,它们将用作额外的关键字参数。

  • shutil. unregister_archive_format(* name *)

    • 从支持的格式列表中删除存档格式* name *。
  • shutil. unpack_archive(* filename * [,* extract_dir * [,* format *]])

    • 解压缩 Files。 * filename *是 Files 的完整路径。
  • extract_dir *是解压缩 Files 的目标目录的名称。如果未提供,则使用当前工作目录。

  • format *是存档格式:“ zip”,“ tar”,“ gztar”,“ bztar”或“ xztar”之一。或在register_unpack_format()注册的任何其他格式。如果未提供,unpack_archive()将使用存档文件 extensions,并查看是否为该 extensions 注册了解压缩程序。如果未找到,则引发ValueError

用参数filenameextract_dirformat引发auditing event shutil.unpack_archive

在 3.7 版中进行了更改:文件名和* extract_dir *接受path-like object

  • shutil. register_unpack_format(* name extensions function * [,* extra_args * [,* description *]])
    • 注册解压缩格式。 * name 是格式的名称,而 extensions *是与该格式相对应的 extensions 的列表,例如 zip 的.zip
  • function *是将用于解压缩 Files 的可调用对象。可调用对象将接收存档的路径,后跟必须将存档提取到的目录。

如果提供,则* extra_args *是(name, value)Tuples 的序列,将作为关键字参数传递给可调用对象。

可以提供* description *来描述格式,并将由get_unpack_formats()函数返回。

  • shutil. unregister_unpack_format(* name *)

    • 取消注册解压缩格式。 * name *是格式的名称。
  • shutil. get_unpack_formats ( )

    • 返回所有已注册格式的列表以进行打包。返回序列的每个元素都是 Tuples(name, extensions, description)

默认情况下,shutil提供以下格式:

    • zip *:ZIP 文件(仅当相应模块可用时,解压缩 zipfile 才有效)。
    • tar *:未压缩的 tar 文件。
    • gztar *:gzip 压缩的 tar 文件(如果zlib模块可用)。
    • bztar *:bzip2 版本的 tar 文件(如果bz2模块可用)。
    • xztar *:xz 的 tar 文件(如果lzma模块可用)。

您可以使用register_unpack_format()注册新格式或为任何现有格式提供自己的拆包程序。

Archiving example

在此示例中,我们创建一个 gzip 压缩的 tar 文件 Files,其中包含在用户的.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 归档的示例

在此示例中,类似于one above,我们展示了如何使用make_archive(),但是这次使用的是* base_dir *。现在,我们具有以下目录结构:

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

在finally存档中,应包含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的情况下(通常情况),pass调用os.get_terminal_size()来查询连接到sys.stdout的终端。

如果由于系统不支持查询或由于我们未连接到终端而无法成功查询终端大小,则使用fallback参数中给出的值。 fallback默认为(80, 24),这是许多终端仿真器使用的默认大小。

返回的值是类型为os.terminal_size的命名 Tuples。

另请参阅:单一 UNIX 规范版本 2 其他环境变量

版本 3.3 中的新Function。