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() 以获取接受目标目录路径的副本。 如果 srcdst 是相同的文件,则会引发 Error。 目标位置必须是可写的; 否则,将引发 IOError 异常。 如果 dst 已经存在,它将被替换。 使用此功能无法复制特殊文件,例如字符或块设备和管道。 srcdst 是以字符串形式给出的路径名。
shutil.copymode(src, dst)
将权限位从 src 复制到 dst。 文件内容、所有者和组不受影响。 srcdst 是以字符串形式给出的路径名。
shutil.copystat(src, dst)
将权限位、上次访问时间、上次修改时间和标志从 src 复制到 dst。 文件内容、所有者和组不受影响。 srcdst 是以字符串形式给出的路径名。
shutil.copy(src, dst)
将文件src复制到文件或目录dst。 如果 dst 是目录,则在指定目录中创建(或覆盖)与 src 具有相同基名的文件。 复制权限位。 srcdst 是以字符串形式给出的路径名。
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,它必须是一个接受三个参数的可调用对象:functionpathexcinfo。 第一个参数 function 是引发异常的函数; 它将是 os.path.islink()os.listdir()os.remove() 或 os.rmdir()[ X183X]。 第二个参数 path 将是传递给 function 的路径名。 第三个参数excinfosys.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. 归档操作

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

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_dirbase_dir 都默认为当前目录。

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

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) 的序列,当使用存档器可调用时,它将用作额外的关键字参数。

descriptionget_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