Сообщить об ошибке.

Примеры использования модуля shutil

В этом разделе приводятся примеры использования функций модуля shutil, которые выполняют высокоуровневые файловые операции, такие как копирование, удаление и архивирование.

Содержание:


Копирование файла:

Функция shutil.copyfile() копирует содержимое источника в место назначения и вызывает исключение IOError, если у него нет разрешения на запись в файл назначения.

>>> import shutil, os
>>> from glob import glob
# создадим временную директорию 
>>> os.mkdir('example')
# создадим тестовый файл
>>> open('example/test_file.txt', 'w').close()
# копирование
>>> shutil.copyfile('example/test_file.txt', 'example/test_file.txt.copy')
# 'example/test-file.txt.copy'

# смотрим результат
>>> pprint.pprint(glob('example/*'))
# ['example/test_file.txt.copy', 'example/test_file.txt']

# удаляем
>>> shutil.rmtree('example')

Функция shutil.copy() интерпретирует имя выходного файла как инструмент командной строки Unix cp. Если путь назначения указан как каталог, а не файл, то в каталоге создается новый файл с использованием его базового имени.

>>> import shutil, os
>>> from glob import glob
# создадим тестовый файл
>>> open('shutil_copy.txt', 'w').close()
# создадим временную директорию 
>>> os.mkdir('example')
>>> glob('example/*')
# []

# копируем
>>> shutil.copy('shutil_copy.txt', 'example')
# 'example/shutil_copy.txt'

# смотрим результат
>>> glob('example/*')
# ['example/shutil_copy.txt']

# удаляем
>>> shutil.rmtree('example')

Рекурсивное копирование каталога:

Функция shutil.copytree() рекурсивно копирует весь каталог.

# для того что бы протестировать функцию copytree()
# создадим иерархию каталогов
import pathlib, itertools, glob, shutil
path = 'test/'
tmp = {'script':'.py', 'text':'.txt'}
for d, ext in tmp.items():
    comb = itertools.combinations([d, 1, 0], r=2)
    for a, b in comb:
        name = f'{a}{b}{ext}'
        pathlib.Path(path, d).mkdir(parents=True, exist_ok=True)
        pathlib.Path(path, d, name).touch(exist_ok=True)

f = glob.glob('test/**/*', recursive=True)
print(f)
# ['test/text', 'test/script', 'test/text/10.txt', 
# 'test/text/text1.txt', 'test/text/text0.txt',
# 'test/script/10.py', 'test/script/script0.py', 
# 'test/script/script1.py']

# копируем
shutil.copytree('test', 'test_cp')
# смотрим результат
f_cp = glob.glob('test_cp/**/*', recursive=True)
print(f_cp)

# ['test/text', 'test/script', 'test/text/10.txt', 
# 'test/text/text1.txt', 'test/text/text0.txt',
# 'test/script/10.py', 'test/script/script0.py', 
# 'test/script/script1.py']

# удаляем
shutil.rmtree('test_cp')
shutil.rmtree('test')

Выборочное рекурсивное копирование файлов каталога:

Пример, который использует помощник shutil.ignore_patterns(). Здесь копируется все, кроме файлов .pyc и файлов или каталогов, чье имя начинается с tmp.

from shutil import copytree, ignore_patterns
copytree(source, destination, ignore=ignore_patterns('*.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)

Рекурсивное удаление каталога:

Работа функции shutil.rmtree(), которая выполняет рекурсивное удаление каталога, демонстрировалась выше. Разберем ситуации посложнее.

В этом примере показано, как удалить дерево каталогов в Windows, где для некоторых файлов установлен бит только для чтения. Он использует обратный вызов onerror, чтобы очистить бит readonly и повторить попытку удаления.

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)

В функции shutil.rmtree(), так же можно использовать помощник shutil.ignore_patterns() для выборочного рекурсивного удаления файлов как это делается в выборочном рекурсивном копировании файлов.

Пример реализации функции shutil.copytree():

Этот пример является реализацией функции shutil.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)

Архивирование каталогов:

В этом примере создадим архив tar-файлов с использованием gzip, содержащий все файлы, найденные в каталоге .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/docs-python/myarchive.tar.gz'

Полученный архив содержит:

~$ tar -tzvf /home/docs-python/myarchive.tar.gz
drwx------ docs-python/docs-python     0 2019-12-17 16:57 ./
-rw------- docs-python/docs-python  1554 2019-12-17 16:53 ./known_hosts
-rw------- docs-python/docs-python  1554 2019-12-17 14:06 ./known_hosts.old
-rw------- docs-python/docs-python  1679 2019-09-16 12:02 ./id_rsa
-rw-r--r-- docs-python/docs-python   399 2019-09-16 12:02 ./id_rsa.pub