Автор оригинала: Doug Hellmann.
Цель:
Файловые операции высокого уровня.
Модуль shutil
включает высокоуровневые файловые операции, такие как копирование и архивирование.
Копирование файлов
copyfile ()
копирует содержимое источника в место назначения и вызывает ошибку IOError
, если у него нет разрешения на запись в файл назначения.
shutil_copyfile.py
import glob import shutil print('BEFORE:', glob.glob('shutil_copyfile.*')) shutil.copyfile('shutil_copyfile.py', 'shutil_copyfile.py.copy') print('AFTER:', glob.glob('shutil_copyfile.*'))
Поскольку функция открывает входной файл для чтения, независимо от его типа, специальные файлы (например, узлы устройств Unix) не могут быть скопированы как новые специальные файлы с помощью copyfile ()
.
$ python3 shutil_copyfile.py BEFORE: ['shutil_copyfile.py'] AFTER: ['shutil_copyfile.py', 'shutil_copyfile.py.copy']
Реализация copyfile ()
использует функцию нижнего уровня copyfileobj ()
. В то время как аргументы для copyfile ()
– это имена файлов, аргументы для copyfileobj ()
– это дескрипторы открытых файлов. Необязательный третий аргумент – это длина буфера, используемая для чтения в блоках.
shutil_copyfileobj.py
import io import os import shutil import sys class VerboseStringIO(io.StringIO): def read(self, n1): next io.StringIO.read(self, n) print('read({}) got {} bytes'.format(n, len(next))) 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, 256)
По умолчанию чтение выполняется с использованием больших блоков. Используйте -1
для одновременного чтения всего ввода или другого положительного целого числа, чтобы установить конкретный размер блока. В этом примере для демонстрации эффекта используются блоки нескольких разных размеров.
$ python3 shutil_copyfileobj.py Default: read(16384) got 166 bytes read(16384) got 0 bytes All at once: read(-1) got 166 bytes read(-1) got 0 bytes Blocks of 256: read(256) got 166 bytes read(256) got 0 bytes
Функция copy ()
интерпретирует имя вывода, как инструмент командной строки Unix cp
. Если указанное место назначения относится к каталогу, а не к файлу, в каталоге создается новый файл с использованием базового имени источника.
shutil_copy.py
import glob import os import shutil os.mkdir('example') print('BEFORE:', glob.glob('example/*')) shutil.copy('shutil_copy.py', 'example') print('AFTER :', glob.glob('example/*'))
Права доступа к файлу копируются вместе с содержимым.
$ python3 shutil_copy.py BEFORE: [] AFTER : ['example/shutil_copy.py']
copy2 ()
работает так же, как copy ()
, но включает время доступа и изменения в метаданные, скопированные в новый файл.
shutil_copy2.py
import os import shutil import time def show_file_info(filename): stat_info os.stat(filename) print(' Mode :', oct(stat_info.st_mode)) print(' Created :', time.ctime(stat_info.st_ctime)) print(' Accessed:', time.ctime(stat_info.st_atime)) print(' Modified:', time.ctime(stat_info.st_mtime)) os.mkdir('example') print('SOURCE:') show_file_info('shutil_copy2.py') shutil.copy2('shutil_copy2.py', 'example') print('DEST:') show_file_info('example/shutil_copy2.py')
Новый файл имеет все те же характеристики, что и старая версия.
$ python3 shutil_copy2.py SOURCE: Mode : 0o100644 Created : Wed Dec 28 19:03:12 2016 Accessed: Wed Dec 28 19:03:49 2016 Modified: Wed Dec 28 19:03:12 2016 DEST: Mode : 0o100644 Created : Wed Dec 28 19:03:49 2016 Accessed: Wed Dec 28 19:03:49 2016 Modified: Wed Dec 28 19:03:12 2016
Копирование метаданных файла
По умолчанию, когда новый файл создается в Unix, он получает разрешения на основе umask текущего пользователя. Чтобы скопировать разрешения из одного файла в другой, используйте copymode ()
.
shutil_copymode.py
import os import shutil import subprocess with open('file_to_change.txt', 'wt') as f: f.write('content') os.chmod('file_to_change.txt', 0o444) print('BEFORE:', oct(os.stat('file_to_change.txt').st_mode)) shutil.copymode('shutil_copymode.py', 'file_to_change.txt') print('AFTER :', oct(os.stat('file_to_change.txt').st_mode))
Этот пример сценария создает файл, который нужно изменить, а затем использует copymode ()
для дублирования разрешений сценария для файла примера.
$ python3 shutil_copymode.py BEFORE: 0o100444 AFTER : 0o100644
Чтобы скопировать другие метаданные о файле, используйте copystat ()
.
shutil_copystat.py
import os import shutil import time def show_file_info(filename): stat_info os.stat(filename) print(' Mode :', oct(stat_info.st_mode)) print(' Created :', time.ctime(stat_info.st_ctime)) print(' Accessed:', time.ctime(stat_info.st_atime)) print(' Modified:', time.ctime(stat_info.st_mtime)) with open('file_to_change.txt', 'wt') as f: f.write('content') os.chmod('file_to_change.txt', 0o444) print('BEFORE:') show_file_info('file_to_change.txt') shutil.copystat('shutil_copystat.py', 'file_to_change.txt') print('AFTER:') show_file_info('file_to_change.txt')
Только разрешения и даты, связанные с файлом, дублируются с помощью copystat ()
.
$ python3 shutil_copystat.py BEFORE: Mode : 0o100444 Created : Wed Dec 28 19:03:49 2016 Accessed: Wed Dec 28 19:03:49 2016 Modified: Wed Dec 28 19:03:49 2016 AFTER: Mode : 0o100644 Created : Wed Dec 28 19:03:49 2016 Accessed: Wed Dec 28 19:03:49 2016 Modified: Wed Dec 28 19:03:46 2016
Работа с деревьями каталогов
shutil
включает три функции для работы с деревьями каталогов. Чтобы скопировать каталог из одного места в другое, используйте copytree ()
. Он рекурсивно проходит через дерево исходных каталогов, копируя файлы в место назначения. Каталог назначения не должен существовать заранее.
shutil_copytree.py
import glob import pprint import shutil print('BEFORE:') pprint.pprint(glob.glob('/tmp/example/*')) shutil.copytree('../shutil', '/tmp/example') print('\nAFTER:') pprint.pprint(glob.glob('/tmp/example/*'))
Аргумент символические ссылки
определяет, копируются ли символические ссылки как ссылки или как файлы. По умолчанию содержимое копируется в новые файлы. Если опция истинна, в целевом дереве создаются новые символические ссылки.
$ python3 shutil_copytree.py BEFORE: [] AFTER: ['/tmp/example/example', '/tmp/example/example.out', '/tmp/example/file_to_change.txt', '/tmp/example/index.rst', '/tmp/example/shutil_copy.py', '/tmp/example/shutil_copy2.py', '/tmp/example/shutil_copyfile.py', '/tmp/example/shutil_copyfile.py.copy', '/tmp/example/shutil_copyfileobj.py', '/tmp/example/shutil_copymode.py', '/tmp/example/shutil_copystat.py', '/tmp/example/shutil_copytree.py', '/tmp/example/shutil_copytree_verbose.py', '/tmp/example/shutil_disk_usage.py', '/tmp/example/shutil_get_archive_formats.py', '/tmp/example/shutil_get_unpack_formats.py', '/tmp/example/shutil_make_archive.py', '/tmp/example/shutil_move.py', '/tmp/example/shutil_rmtree.py', '/tmp/example/shutil_unpack_archive.py', '/tmp/example/shutil_which.py', '/tmp/example/shutil_which_regular_file.py']
copytree ()
принимает два вызываемых аргумента для управления своим поведением. Аргумент ignore
вызывается с именем каждого каталога или подкаталога, который копируется вместе со списком содержимого каталога. Он должен вернуть список элементов, которые следует скопировать. Аргумент copy_function
вызывается для фактического копирования файла.
shutil_copytree_verbose.py
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_functionverbose_copy, ignoreshutil.ignore_patterns('*.py'), ) print('\nAFTER:') pprint.pprint(glob.glob('/tmp/example/*'))
В этом примере ignore_patterns ()
используется для создания функции игнорирования, чтобы пропустить копирование исходных файлов Python. verbose_copy ()
печатает имена файлов по мере их копирования, а затем использует copy2 ()
, функцию копирования по умолчанию, для создания копий.
$ python3 shutil_copytree_verbose.py BEFORE: [] copying '../shutil/example.out' to '/tmp/example/example.out' copying '../shutil/file_to_change.txt' to '/tmp/example/file_to_change.txt' copying '../shutil/index.rst' to '/tmp/example/index.rst' AFTER: ['/tmp/example/example', '/tmp/example/example.out', '/tmp/example/file_to_change.txt', '/tmp/example/index.rst']
Чтобы удалить каталог и его содержимое, используйте rmtree ()
.
shutil_rmtree.py
import glob import pprint import shutil print('BEFORE:') pprint.pprint(glob.glob('/tmp/example/*')) shutil.rmtree('/tmp/example') print('\nAFTER:') pprint.pprint(glob.glob('/tmp/example/*'))
По умолчанию ошибки возникают как исключения, но их можно игнорировать, если второй аргумент истинен, а в третьем аргументе может быть указана специальная функция обработчика ошибок.
$ python3 shutil_rmtree.py BEFORE: ['/tmp/example/example', '/tmp/example/example.out', '/tmp/example/file_to_change.txt', '/tmp/example/index.rst'] AFTER: []
Чтобы переместить файл или каталог из одного места в другое, используйте move ()
.
shutil_move.py
import glob import shutil with open('example.txt', 'wt') as f: f.write('contents') print('BEFORE: ', glob.glob('example*')) shutil.move('example.txt', 'example.out') print('AFTER : ', glob.glob('example*'))
Семантика аналогична семантике команды Unix mv
. Если источник и место назначения находятся в одной файловой системе, источник переименовывается. В противном случае источник копируется в место назначения, а затем источник удаляется.
$ python3 shutil_move.py BEFORE: ['example.txt'] AFTER : ['example.out']
Поиск файлов
Функция which ()
сканирует путь поиска в поисках именованного файла. Типичный вариант использования – найти исполняемую программу на пути поиска оболочки, заданном в переменной среды PATH
.
shutil_which.py
import shutil print(shutil.which('virtualenv')) print(shutil.which('tox')) print(shutil.which('no-such-program'))
Если не удается найти файл, соответствующий параметрам поиска, which ()
возвращает None
.
$ python3 shutil_which.py /Users/dhellmann/Library/Python/3.5/bin/virtualenv /Users/dhellmann/Library/Python/3.5/bin/tox None
which ()
принимает аргументы для фильтрации на основе разрешений, имеющихся у файла, и пути поиска для проверки. Аргумент path
по умолчанию имеет значение os.environ ('PATH')
, но может быть любой строкой, содержащей имена каталогов, разделенные os.pathsep
. Аргумент mode
должен быть битовой маской, соответствующей разрешениям файла. По умолчанию маска ищет исполняемые файлы, но в следующем примере используется читаемая битовая маска и альтернативный путь поиска для поиска файла конфигурации.
shutil_which_regular_file.py
import os import shutil path os.pathsep.join([ '.', os.path.expanduser('~/pymotw'), ]) mode os.F_OK | os.R_OK filename shutil.which( 'config.ini', modemode, pathpath, ) print(filename)
По-прежнему существует состояние гонки при поиске читаемых файлов таким образом, потому что за время между поиском файла и фактической попыткой его использования файл может быть удален или его разрешения могут быть изменены.
$ touch config.ini $ python3 shutil_which_regular_file.py ./config.ini
Архивы
Стандартная библиотека Python включает множество модулей для управления архивными файлами, такими как tarfile и zipfile. Также в shutil
есть несколько функций более высокого уровня для создания и извлечения архивов. get_archive_formats ()
возвращает последовательность имен и описаний для форматов, поддерживаемых в текущей системе.
shutil_get_archive_formats.py
import shutil for format, description in shutil.get_archive_formats(): print('{:<5}: {}'.format(format, description))
Поддерживаемые форматы зависят от того, какие модули и базовые библиотеки доступны, поэтому вывод для этого примера может измениться в зависимости от того, где он запущен.
$ python3 shutil_get_archive_formats.py bztar: bzip2'ed tar-file gztar: gzip'ed tar-file tar : uncompressed tar file xztar: xz'ed tar-file zip : ZIP file
Используйте make_archive ()
, чтобы создать новый архивный файл. Его входные данные предназначены для наилучшей поддержки рекурсивного архивирования всего каталога и всего его содержимого. По умолчанию он использует текущий рабочий каталог, так что все файлы и подкаталоги отображаются на верхнем уровне архива. Чтобы изменить это поведение, используйте аргумент root_dir
для перехода к новой относительной позиции в файловой системе и аргумент base_dir
, чтобы указать каталог для добавления в архив.
shutil_make_archive.py
import logging import shutil import sys import tarfile logging.basicConfig( format'%(message)s', streamsys.stdout, levellogging.DEBUG, ) logger logging.getLogger('pymotw') print('Creating archive:') shutil.make_archive( 'example', 'gztar', root_dir'..', base_dir'shutil', loggerlogger, ) print('\nArchive contents:') with tarfile.open('example.tar.gz', 'r') as t: for n in t.getnames(): print(n)
Этот пример начинается в исходном каталоге примеров для shutil
и перемещается на один уровень вверх в файловой системе, а затем добавляет каталог shutil
в архив tar, сжатый с помощью gzip. Модуль ведения журнала настроен на отображение сообщений от make_archive ()
о том, что он делает.
$ python3 shutil_make_archive.py Creating archive: changing into '..' Creating tar archive changing back to '...' Archive contents: shutil shutil/config.ini shutil/example.out shutil/file_to_change.txt shutil/index.rst shutil/shutil_copy.py shutil/shutil_copy2.py shutil/shutil_copyfile.py shutil/shutil_copyfileobj.py shutil/shutil_copymode.py shutil/shutil_copystat.py shutil/shutil_copytree.py shutil/shutil_copytree_verbose.py shutil/shutil_disk_usage.py shutil/shutil_get_archive_formats.py shutil/shutil_get_unpack_formats.py shutil/shutil_make_archive.py shutil/shutil_move.py shutil/shutil_rmtree.py shutil/shutil_unpack_archive.py shutil/shutil_which.py shutil/shutil_which_regular_file.py
shutil
поддерживает реестр форматов, которые могут быть распакованы в текущей системе, доступный через get_unpack_formats ()
.
shutil_get_unpack_formats.py
import shutil for format, exts, description in shutil.get_unpack_formats(): print('{:<5}: {}, names ending in {}'.format( format, description, exts))
Этот реестр отличается от реестра для создания архивов, потому что он также включает общие расширения файлов, используемые для каждого формата, так что функция извлечения архива может угадать, какой формат использовать на основе расширения файла.
$ python3 shutil_get_unpack_formats.py bztar: bzip2'ed tar-file, names ending in ['.tar.bz2', '.tbz2'] gztar: gzip'ed tar-file, names ending in ['.tar.gz', '.tgz'] tar : uncompressed tar file, names ending in ['.tar'] xztar: xz'ed tar-file, names ending in ['.tar.xz', '.txz'] zip : ZIP file, names ending in ['.zip']
Извлеките архив с помощью unpack_archive ()
, передав имя файла архива и, возможно, каталог, в который он должен быть извлечен. Если каталог не указан, используется текущий каталог.
shutil_unpack_archive.py
import pathlib import shutil import sys import tempfile with tempfile.TemporaryDirectory() as d: print('Unpacking archive:') shutil.unpack_archive( 'example.tar.gz', extract_dird, ) print('\nCreated:') prefix_len len(d) + 1 for extracted in pathlib.Path(d).rglob('*'): print(str(extracted)[prefix_len:])
В этом примере unpack_archive ()
может определять формат архива, потому что имя файла заканчивается на tar.gz
, и это значение связано с gztar
format в реестре формата распаковки.
$ python3 shutil_unpack_archive.py Unpacking archive: Created: shutil shutil/config.ini shutil/example.out shutil/file_to_change.txt shutil/index.rst shutil/shutil_copy.py shutil/shutil_copy2.py shutil/shutil_copyfile.py shutil/shutil_copyfileobj.py shutil/shutil_copymode.py shutil/shutil_copystat.py shutil/shutil_copytree.py shutil/shutil_copytree_verbose.py shutil/shutil_disk_usage.py shutil/shutil_get_archive_formats.py shutil/shutil_get_unpack_formats.py shutil/shutil_make_archive.py shutil/shutil_move.py shutil/shutil_rmtree.py shutil/shutil_unpack_archive.py shutil/shutil_which.py shutil/shutil_which_regular_file.py
Пространство файловой системы
Может быть полезно проверить локальную файловую систему, чтобы узнать, сколько места доступно, прежде чем выполнять длительную операцию, которая может исчерпать это пространство. disk_usage ()
возвращает кортеж с общим пространством, используемым в данный момент объемом и оставшимся свободным объемом.
shutil_disk_usage.py
import shutil total_b, used_b, free_b shutil.disk_usage('.') gib 2 ** 30 # GiB> gb 10 ** 9 # GB> 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))
Значения, возвращаемые функцией disk_usage ()
, представляют собой количество байтов, поэтому пример программы преобразует их в более удобочитаемые единицы перед их печатью.
$ python3 shutil_disk_usage.py Total: 499.42 GB 465.12 GiB Used : 246.68 GB 229.73 GiB Free : 252.48 GB 235.14 GiB
Смотрите также
- стандартная библиотека документации для shutil
- Сжатие и архивирование данных – модули для работы с форматами архивирования и сжатия.