6.16.shutil
import shutil
import os
from toolkit import H
复制文件
shutil.copyfile(src, dst, follow_symlinks=True)
copyfile()
复制源文件的内容到目标位置,如果没有创建新文件的权限将会引发 IOError
,如果dst
已存在,则会被替换。src
、dst
不能是目录。一些特殊的文件(例如 Unix 设备)是不能使用它进行复制的,因为 copyfile()
不管文件的类型如何,都会打开进行读取。
shutil.copyfileobj(fsrc, fdst, length=16384)
copyfile()
是调用低级方法 copyfileobj()
实现的。但传入 copyfile()
的参数是文件名称,而传入 copyfileobj()
是打开的文件描述符。可选的第三个参数是用来设置读取块的大小。默认行为是使用大块读取。使用 -1
一次性读取所有输入,或者使用一个正整数设定一个具体的区块大小。下面的示例代码使用了不同的块大小展示效果。
import io
class VerboseStringIO(io.StringIO):
def read(self, n=-1):
next = io.StringIO.read(self, n)
print(f'read({n}) got {len(next)} bytes')
return next
lorem_ipsum = '''Lorem ipsum dolor sit amet, consectetuer
adipiscing elit. Vestibulum aliquam mollis dolor. Donec
vulputate nunc ut diam. Ut rutrum mi vel sem. Vestibulum
ante ipsum.
'''
print('Default:')
input = VerboseStringIO(lorem_ipsum)
output = io.StringIO()
shutil.copyfileobj(input, output)
print()
print('All at once:')
input = VerboseStringIO(lorem_ipsum)
output = io.StringIO()
shutil.copyfileobj(input, output, -1)
print()
print('Blocks of 256:')
input = VerboseStringIO(lorem_ipsum)
output = io.StringIO()
shutil.copyfileobj(input, output, 100)
Default:
read(16384) got 167 bytes
read(16384) got 0 bytes
All at once:
read(-1) got 167 bytes
read(-1) got 0 bytes
Blocks of 256:
read(100) got 100 bytes
read(100) got 67 bytes
read(100) got 0 bytes
shutil.copy(src, dst, follow_symlinks=True)
复制一个文件到目标路径,如果目标路径是一个目录,而不是文件,那么将会在这个目录中创建一个与源文件同名的新文件。copy()
函数实际上是先后调用了 copyfile()
函数和copymode()
函数,因此文件的权限将会随着内容一起复制。copy()
函数会像 Unix 命令行工具 cp 那样打印出新文件的路径。
shutil.copy2(src, dst, follow_symlinks=True)
copy2()
类似 copy()
,但先后调用的是 copyfile()
函数和copystat()
函数,因此在复制时会包含元数据中的访问和修改时间。但新旧文件的权限可能不一样,因为默认情况下,Unix 上创建一个新文件的时候,它的权限依赖于当前用户的 umask。如果要复制文件权限,请使用 copymode()
。
shutil.copymode(src, dst, follow_symlinks=True)
从src复制权限位到dst。该文件的内容,所有者和组不受影响。
shutil.copystat(src, dst, follow_symlinks=True)
从src复制权限位、最后访问时间、最后修改时间、文件的flags到dst。该文件的内容,所有者和组不受影响。在 Linux 中,copystat
会在可能的情况下复制"extended attributes",
shutil.copytree(src, dst, symlinks=False, ignore=None,
copy_function=shutil.copy2,
ignore_dangling_symlinks=False)
把 src 目录复制到 dst,src 和 dst 都只能是目录,且 dst 必须不存在。
symlinks
参数控制符号链接是被复制为链接还是文件。默认为False
,会将符号链接指向的文件复制到 dst,因此,如果符号链接指向的文件已经不存在,则会引发异常。如果这个参数是 true
,将会在 dst 中创建新的符号链接。
ignore_dangling_symlinks
参数为True
时,如果 src 存在损坏的 symbolic link,也不会抛出异常。
copytree()
函数使用两个回调参数控制它的行为。ignore
参数在每个目录或者子目录以及目录中内容被复制时调用,它返回一个应该被复制的内容列表。copy_function
参数用于在文件实际复制时调用。
import glob
import pprint
import shutil
def verbose_copy(src, dst):
print('copying\n {!r}\n to {!r}'.format(src, dst))
return shutil.copy2(src, dst)
print('BEFORE:')
pprint.pprint(glob.glob('/tmp/example/*'))
print()
shutil.copytree(
'../shutil', '/tmp/example',
copy_function=verbose_copy,
ignore=shutil.ignore_patterns('*.py'),
)
print('\nAFTER:')
pprint.pprint(glob.glob('/tmp/example/*'))
这个例子中,ignore_patterns()
用于去创建一个忽略方法跳过 Python 源文件。verbose_copy()
打印复制的文件名称然后调用 copy2()
复制,它是默认的复制方法。
删除文件
shutil.rmtree(path, ignore_errors=False, onerror=None)
错误默认情况下引发为异常,但是如果第二个参数为 true 将被忽略,也可以通过第三个参数提供一个错误处理方法。
移动文件
shutil.move(src, dst, copy_function=shutil.copy2)
原理类似于 Unix 命令 mv 。如果源文件和目标文件都存在,源文件将会被重命名。否则源文件被复制到目的地然后被删除。
查找文件
shutil.which(cmd, mode=1, path=None)
which()
方法会按照一个搜索路径查找文件。典型的使用场景是在环境变量 PATH
定义的路径中查找可执行程序的位置。如果没有找到文件,which()
返回 None
。
print(shutil.which("cmd"))
C:\WINDOWS\system32\cmd.EXE
which()
方法接收参数依据文件权限以及搜索路径进行过滤。path
参数默认是 os.environ('PATH')
,但是可以是任何由 os.pathsep
分隔的字符串。mode
参数应该是一个匹配文件权限的位掩码。默认情况下查找可执行文件。下列的例子使用了可读掩码以及一个搜索路径去查找配置文件。
path = os.pathsep.join([
'.',
os.path.expanduser('~/pymotw'),
])
mode = os.F_OK | os.R_OK
filename = shutil.which('config.ini', mode=mode, path=path)
解压缩
Python 标准库包含了许多模块用于管理压缩文件,例如 tarfile 和 zipfile。shutil 模块中也有几个高阶方法用于解压缩文件。
shutil
模块维护了一个可在当前系统上压缩、解压缩的格式注册表,通过get_archive_formats()
和 get_unpack_formats()
访问。支持的格式依赖于哪些模块和底层库可用。
shutil.get_archive_formats()
[('bztar', "bzip2'ed tar-file"),
('gztar', "gzip'ed tar-file"),
('tar', 'uncompressed tar file'),
('xztar', "xz'ed tar-file"),
('zip', 'ZIP file')]
解压缩的注册表不同于创建压缩文件的注册表,因为它还包括用于每种格式的常用文件扩展名,以便解压方法根据文件扩展名猜测要使用的格式。
shutil.get_unpack_formats()
[('bztar', ['.tar.bz2', '.tbz2'], "bzip2'ed tar-file"),
('gztar', ['.tar.gz', '.tgz'], "gzip'ed tar-file"),
('tar', ['.tar'], 'uncompressed tar file'),
('xztar', ['.tar.xz', '.txz'], "xz'ed tar-file"),
('zip', ['.zip'], 'ZIP file')]
也可以使用 register_archive_format()
和 register_unpack_format()
函数注册自定义的压缩、解压缩函数。
shutil.register_archive_format(name, function, extra_args=None,
description='')
shutil.register_unpack_format(name, extensions, function, extra_args=None,
description='')
或者使用 unregister_archive_format()
和 unregister_unpack_format()
函数取消注册压缩、解压缩函数。
shutil.unregister_archive_format(name)
shutil.unregister_unpack_format(name)
可以使用 make_archive()
创建一个新的压缩文件。make_archive()
的参数似乎有点混乱,可以参考以下简单的用法。
shutil.make_archive(base_name, format, root_dir=None, base_dir=None,
verbose=0, dry_run=0, owner=None, group=None, logger=None)
import os, shutil
def make_archive(source, destination):
base = os.path.basename(destination)
name = base.split('.')[0]
format = base.split('.')[1]
archive_from = os.path.dirname(source)
archive_to = os.path.basename(source.strip(os.sep))
print(source, destination, archive_from, archive_to)
shutil.make_archive(name, format, archive_from, archive_to)
shutil.move('%s.%s'%(name,format), destination)
make_archive('/path/to/folder', '/path/to/folder.zip')
https://www.thinbug.com/q/45245079
使用 unpack_archive()
解压文件,传入压缩文件名以及可选的解压目录,默认是当前目录。
shutil.unpack_archive(filename, extract_dir=None, format=None)
filename
是压缩档案的名称。extract_dir
是解压的目标目录。如果未提供,则使用当前工作目录。format
是压缩档案格式:zip 、tar、gztar、bztar、xztar 其中之一,或着任何其他的注册格式。如果未提供,unpack_archive
将使用文件扩展名,并查看是否为该扩展名注册了解压程序。如果没有找到,则会引发ValueError
。
文件系统空间
disk_usage()
返回一个元组表示系统总空间,当前使用总量以及剩余总量,其单位为字节。
shutil.disk_usage(path)
import shutil
total_b, used_b, free_b = shutil.disk_usage('.')
gib = 2 ** 30 # GiB == gibibyte
gb = 10 ** 9 # GB == gigabyte
print('Total: {:6.2f} GB {:6.2f} GiB'.format(
total_b / gb, total_b / gib))
print('Used : {:6.2f} GB {:6.2f} GiB'.format(
used_b / gb, used_b / gib))
print('Free : {:6.2f} GB {:6.2f} GiB'.format(
free_b / gb, free_b / gib))
Total: 479.88 GB 446.92 GiB
Used : 318.18 GB 296.33 GiB
Free : 161.69 GB 150.59 GiB
获取终端窗口的大小
shutil.get_terminal_size(fallback=(80, 24))
忽略函数
shutil.ignore_patterns(patterns)
ignore_patterns
返回一个函数,可以用作 copytree()
的函数的 ignore
参数。以下表示忽略 python 文件。
shutil.ignore_patterns('*.py')
<function shutil.ignore_patterns.<locals>._ignore_patterns(path, names)>