10.10. shutil — 高级文件操作 — Python 文档

来自菜鸟教程
Python/docs/2.7/library/shutil
跳转至:导航、​搜索

10.10. 休蒂尔 — 高级文件操作

源代码: :source:`Lib/shutil.py`



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

警告

即使是更高级别的文件复制功能(shutil.copy(), shutil.copy2())也无法复制所有文件元数据。

在 POSIX 平台上,这意味着文件所有者和组以及 ACL 都将丢失。 在 Mac OS 上,不使用资源分支和其他元数据。 这意味着资源将丢失,文件类型和创建者代码将不正确。 在 Windows 上,不会复制文件所有者、ACL 和备用数据流。


10.10.1. 目录和文件操作

shutil.copyfileobj(fsrc, fdst[, length])
将类文件对象 fsrc 的内容复制到类文件对象 fdst。 整数 length(如果给定)是缓冲区大小。 特别是,负 length 值意味着复制数据而不在块中循环遍历源数据; 默认情况下,数据是分块读取的,以避免不受控制的内存消耗。 注意,如果fsrc对象的当前文件位置不为0,则只会复制从当前文件位置到文件末尾的内容。
shutil.copyfile(src, dst)
将名为 src 的文件的内容(无元数据)复制到名为 dst 的文件中。 dst 必须是完整的目标文件名; 查看 shutil.copy() 以获取接受目标目录路径的副本。 如果 src 和 dst 是相同的文件,则会引发 Error。 目标位置必须是可写的; 否则,将引发 IOError 异常。 如果 dst 已经存在,它将被替换。 使用此功能无法复制特殊文件,例如字符或块设备和管道。 src 和 dst 是以字符串形式给出的路径名。
shutil.copymode(src, dst)
将权限位从 src 复制到 dst。 文件内容、所有者和组不受影响。 src 和 dst 是以字符串形式给出的路径名。
shutil.copystat(src, dst)
将权限位、上次访问时间、上次修改时间和标志从 src 复制到 dst。 文件内容、所有者和组不受影响。 src 和 dst 是以字符串形式给出的路径名。
shutil.copy(src, dst)
将文件src复制到文件或目录dst。 如果 dst 是目录,则在指定目录中创建(或覆盖)与 src 具有相同基名的文件。 复制权限位。 src 和 dst 是以字符串形式给出的路径名。
shutil.copy2(src, dst)

与 copy() 相同,除了 copy2() 也尝试保留文件元数据。

copy2() 使用 copystat() 复制文件元数据。 请参阅 copystat() 了解更多信息。

shutil.ignore_patterns(\*patterns)

此工厂函数创建一个函数,该函数可用作 copytree()' 的 ignore 参数的可调用函数,忽略与 glob 样式 之一匹配的文件和目录] 模式 提供。 请参阅下面的示例。

2.6 版中的新功能。

shutil.copytree(src, dst, symlinks=False, ignore=None)

递归复制以 src 为根的整个目录树。 以dst命名的目标目录必须不存在; 它将被创建以及丢失的父目录。 使用copystat()复制目录的权限和时间,使用shutil.copy2()复制单个文件。

如果 symlinks 为真,则源树中的符号链接在新树中表示为符号链接,但不会复制原始链接的元数据; 如果为 false 或省略,则链接文件的内容和元数据将复制到新树中。

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

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

应将其源代码视为示例而不是最终工具。

在 2.3 版更改:如果在复制过程中发生任何异常,而不是打印消息,则会引发 Error。

2.5 版更改: 创建创建 dst 所需的中间目录,而不是引发错误。 使用 copystat() 复制目录的权限和时间。

在 2.6 版中更改: 添加了 ignore 参数以能够影响正在复制的内容。

shutil.rmtree(path[, ignore_errors[, onerror]])

删除整个目录树; path 必须指向一个目录(但不是指向目录的符号链接)。 如果 ignore_errors 为真,则删除失败导致的错误将被忽略; 如果为 false 或省略,则通过调用由 onerror 指定的处理程序来处理此类错误,或者,如果省略,则引发异常。

如果提供了 onerror,它必须是一个接受三个参数的可调用对象:function、path 和 excinfo。 第一个参数 function 是引发异常的函数; 它将是 os.path.islink()、os.listdir()、os.remove() 或 os.rmdir()[ X183X]。 第二个参数 path 将是传递给 function 的路径名。 第三个参数excinfo是sys.exc_info()返回的异常信息。 不会捕获由 onerror 引发的异常。

在 2.6 版更改: 明确检查 path 是否为符号链接并在这种情况下引发 OSError。

shutil.move(src, dst)

递归地将文件或目录 (src) 移动到另一个位置 (dst)。

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

如果目标在当前文件系统上,则使用 os.rename()。 否则,将 src 复制(使用 shutil.copy2())到 dst,然后删除。

2.3 版中的新功能。

exception shutil.Error

此异常收集在多文件操作期间引发的异常。 对于 copytree(),异常参数是一个 3 元组列表(srcname, dstname, exception)。

2.3 版中的新功能。

10.10.1.1。 复制树示例

这个例子是上面描述的 copytree() 函数的实现,省略了文档字符串。 它演示了该模块提供的许多其他功能。

def copytree(src, dst, symlinks=False, ignore=None):
    names = os.listdir(src)
    if ignore is not None:
        ignored_names = ignore(src, names)
    else:
        ignored_names = set()

    os.makedirs(dst)
    errors = []
    for name in names:
        if name in ignored_names:
            continue
        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, ignore)
            else:
                copy2(srcname, dstname)
            # XXX What about devices, sockets etc.?
        except (IOError, os.error) 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 WindowsError:
        # can't copy file access times on Windows
        pass
    except OSError as why:
        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)

10.10.2. 归档操作

还提供了用于创建和读取压缩和存档文件的高级实用程序。 它们依赖于 zipfile 和 tarfile 模块。

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

创建一个存档文件(例如。 zip 或 tar)并返回其名称。

base_name 是要创建的文件的名称,包括路径,减去任何特定于格式的扩展名。 format 是存档格式:“zip”之一(如果 zlib 模块或外部 zip 可执行文件可用)、“tar”、“gztar”(如果zlib 模块可用)或“bztar”(如果 bz2 模块可用)。

root_dir 是一个目录,它将成为存档的根目录; IE。 我们通常在创建存档之前 chdir 进入 root_dir。

base_dir 是我们开始归档的目录; IE。 base_dir 将是存档中所有文件和目录的公共前缀。

root_dir 和 base_dir 都默认为当前目录。

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

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

2.7 版中的新功能。

shutil.get_archive_formats()

返回支持的归档格式列表。 返回序列的每个元素都是一个元组 (name, description)。

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

  • zip:ZIP 文件(如果 zlib 模块或外部 zip 可执行文件可用)。

  • tar:未压缩的 tar 文件。

  • gztar:gzip 压缩的 tar 文件(如果 zlib 模块可用)。

  • bztar:bzip2 压缩的 tar 文件(如果 bz2 模块可用)。

您可以使用 register_archive_format() 注册新格式或为任何现有格式提供您自己的存档器。

2.7 版中的新功能。

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

为 name 格式注册存档器。 function 是一个可调用的,用于调用归档器。

如果给定,extra_args 是一个 (name, value) 的序列,当使用存档器可调用时,它将用作额外的关键字参数。

description 由 get_archive_formats() 使用,它返回存档器列表。 默认为空列表。

2.7 版中的新功能。

shutil.unregister_archive_format(name)

从支持的格式列表中删除存档格式 name。

2.7 版中的新功能。

10.10.2.1。 归档示例

在此示例中,我们创建了一个 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