shutil — Operaciones de archivo de alto nivel¶
Propósito: | Operaciones de archivo de alto nivel. |
---|
El módulo shutil
incluye operaciones de archivos de alto nivel como copiar
y archivar.
Copiar archivos¶
copyfile()
copia los contenidos de la fuente al destino y genera
IOError
si no tiene permiso para escribir el archivo de destino.
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.*'))
Debido a que la función abre el archivo de entrada para la lectura,
independientemente de su tipo, los archivos especiales (como los nodos de
dispositivos Unix) no se pueden copiar como nuevos archivos especiales con
copyfile()
.
$ python3 shutil_copyfile.py
BEFORE: ['shutil_copyfile.py']
AFTER: ['shutil_copyfile.py', 'shutil_copyfile.py.copy']
La implementación de copyfile()
usa la función de bajo nivel
copyfileobj()
. Mientras que los argumentos para copyfile()
son los
nombres de archivo, los argumentos para copyfileobj()
son identificadores
de archivos abiertos. El tercer argumento opcional es una longitud de
buffer para usar leyendo en bloques.
import io
import os
import shutil
import sys
class VerboseStringIO(io.StringIO):
def read(self, n=-1):
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)
El comportamiento predeterminado es leer usando bloques grandes. Utiliza
-1
para leer toda la entrada en un momento u otro entero positivo para
establecer una tamaño específico del bloque. Este ejemplo usa varios tamaños
de bloques diferentes para mostrar el efecto.
$ 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
La función copy()
interpreta el nombre de salida como la herramienta Unix
de línea de comandos cp
. Si el destino mencionado se refiere a un
directorio en lugar de un archivo, se crea un nuevo archivo en el directorio
utilizando el nombre base de la fuente.
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/*'))
Los permisos del archivo se copian junto con los contenidos.
$ python3 shutil_copy.py
BEFORE: []
AFTER : ['example/shutil_copy.py']
copy2()
funciona como copy()
, pero incluye los tiempos de acceso y de
modificación en los meta datos copiados al nuevo archivo.
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')
El nuevo archivo tiene todas las mismas características que la versión anterior.
$ 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
Copiar meta datos de archivos¶
Por defecto, cuando se crea un nuevo archivo bajo Unix, éste recibe permisos
basados en la umask del usuario actual. Para copiar los permisos de un archivo
a otro, usa copymode()
.
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))
Esta secuencias de comandos de ejemplo crea un archivo para ser modificado,
luego usa copymode()
para duplicar los permisos de la secuencia de comandos
al archivo de ejemplo
$ python3 shutil_copymode.py
BEFORE: 0o100444
AFTER : 0o100644
Para copiar otros meta datos sobre el archivo usa copystat()
.
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')
Solo se duplican los permisos y las fechas asociadas al archivo con
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
Trabajar con árboles de directorio¶
shutil
incluye tres funciones para trabajar con el directorio arboles.
Para copiar un directorio de un lugar a otro, use copytree()
. Ésta visita
recursivamente el árbol de directorios de origen, copiando archivos al destino.
El directorio de destino no debe existen de antemano.
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/*'))
El argumento symlinks
controla si los enlaces simbólicos se copian como
enlaces o como archivos. El valor predeterminado es copiar el contenido a
nuevos archivos. Si la opción es verdadera, se crean nuevos enlaces simbólicos
dentro del árbol de destino.
$ 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()
acepta dos argumentos invocables para controlar su
comportamiento. El argumento ignore
se llama con el nombre de cada uno
directorio o subdirectorio que se copia junto con una lista de los contenidos
del directorio. Debe devolver una lista de elementos que debe ser copiado. El
argumento copy_function
se llama para copiar el archivo.
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/*'))
En el ejemplo, ignore_patterns()
se usa para crear una función para omitir
la copia de archivos fuente de Python. verbose_copy()
imprime los nombres
de los archivos a medida que se copian y luego usa copy2()
, la función de
copia por defecto, para realizar las copias.
$ 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']
Para eliminar un directorio y su contenido, usa rmtree()
.
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/*'))
Los errores se generan como excepciones de forma predeterminada, pero se pueden ignorar si el segundo argumento es verdadero, y una función especial de control de errores puede ser prevista en el tercer argumento.
$ python3 shutil_rmtree.py
BEFORE:
['/tmp/example/example',
'/tmp/example/example.out',
'/tmp/example/file_to_change.txt',
'/tmp/example/index.rst']
AFTER:
[]
Para mover un archivo o directorio de un lugar a otro, use mover()
.
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*'))
Las semánticas son similares a las del comando mv
de Unix. Si la fuente y
el destino están dentro del mismo sistema de archivos, la fuente es renombrada.
De lo contrario, la fuente se copia al destino y luego la fuente es eliminada
$ python3 shutil_move.py
BEFORE: ['example.txt']
AFTER : ['example.out']
Encontrar archivos¶
La función which()
escanea una ruta de búsqueda buscando un archivo con
nombre. El caso de uso típico es encontrar un programa ejecutable en la ruta
de búsqueda del shell definida en la variable de entorno PATH
.
import shutil
print(shutil.which('virtualenv'))
print(shutil.which('tox'))
print(shutil.which('no-such-program'))
Si no se puede encontrar un archivo que coincida con los parámetros de
búsqueda, which()
devuelve None
.
$ python3 shutil_which.py
/Users/dhellmann/Library/Python/3.5/bin/virtualenv
/Users/dhellmann/Library/Python/3.5/bin/tox
None
which()
toma argumentos para filtrar en función de los permisos que el
archivo tiene, y la ruta de búsqueda para examinar. El argumento path
es
por defecto os.environ('PATH')
, pero puede ser cualquier cadena que
contenga nombres de directorio separados por os.pathsep
. El argumento
mode
debe ser una máscara de bits que coincide con los permisos del
archivo. Por defecto la máscara busca archivos ejecutables, pero el siguiente
ejemplo utiliza una máscara de bits de archivo legible y una ruta de búsqueda
alternativa para encontrar un archivo de configuración.
import os
import shutil
path = os.pathsep.join([
'.',
os.path.expanduser('~/pymotw'),
])
mode = os.F_OK | os.R_OK
filename = shutil.which(
'config.ini',
mode=mode,
path=path,
)
print(filename)
Todavía hay un problema buscando archivos legibles de esta manera, porque en el tiempo entre encontrar el archivo y realmente intentar utilizarlo, el archivo puede ser eliminado o sus permisos pueden ser cambiados.
$ touch config.ini
$ python3 shutil_which_regular_file.py
./config.ini
Archivos¶
La biblioteca estándar de Python incluye muchos módulos para administrar el
archivo archivos como tarfile
y zipfile
. También hay varias
funciones de alto nivel para crear y extraer archivos en shutil
.
get_archive_formats()
devuelve una secuencia de nombres y descripciones de
los formatos soportados en el sistema actual.
import shutil
for format, description in shutil.get_archive_formats():
print('{:<5}: {}'.format(format, description))
Los formatos admitidos dependen de qué módulos y bibliotecas subyacentes están disponibles, por lo que la salida de este ejemplo puede cambiar en función de donde se corre.
$ 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
Usa make_archive()
para crear un nuevo archivo. Sus entradas son diseñadas
para admitir mejor el archivado de un directorio completo y todos sus
contenidos, recursivamente. Por defecto utiliza el directorio de trabajo
actual, para que todos los archivos y subdirectorios aparezcan en el nivel
superior del archivo. Para cambiar ese comportamiento, usa el argumento
root_dir
para pasar a una nueva posición relativa en el sistema de archivos
y el argumento base_dir
para especificar un directorio para agregar al
archivo.
import logging
import shutil
import sys
import tarfile
logging.basicConfig(
format='%(message)s',
stream=sys.stdout,
level=logging.DEBUG,
)
logger = logging.getLogger('pymotw')
print('Creating archive:')
shutil.make_archive(
'example', 'gztar',
root_dir='..',
base_dir='shutil',
logger=logger,
)
print('\nArchive contents:')
with tarfile.open('example.tar.gz', 'r') as t:
for n in t.getnames():
print(n)
Este ejemplo comienza dentro del directorio de origen para los ejemplos de
shutil
y sube un nivel en el sistema de archivos, luego agrega el
directorio shutil
a un archivo tar comprimido con gzip. El módulo
logging
está configurado para mostrar mensajes de make_archive()
sobre lo que está haciendo.
$ 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
mantiene un registro de formatos que se pueden desempaquetar en el
sistema actual, accesible a través de get_unpack_formats()
.
import shutil
for format, exts, description in shutil.get_unpack_formats():
print('{:<5}: {}, names ending in {}'.format(
format, description, exts))
Este registro es diferente del registro para crear archivos porque también incluye extensiones de archivo comunes usadas para cada formato de modo que la función para extraer un archivo pueda adivinar qué formato utilizar en base a la extensión de archivo.
$ 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']
Extrae el archivo con unpack_archive()
, pasando el nombre de archivo y
opcionalmente el directorio donde debería ser extraído. Si no se da ningún
directorio, se usa el directorio actual.
import pathlib
import shutil
import sys
import tempfile
with tempfile.TemporaryDirectory() as d:
print('Unpacking archive:')
shutil.unpack_archive(
'example.tar.gz',
extract_dir=d,
)
print('\nCreated:')
prefix_len = len(d) + 1
for extracted in pathlib.Path(d).rglob('*'):
print(str(extracted)[prefix_len:])
En este ejemplo, unpack_archive()
es capaz de determinar el formato del
archivo porque el nombre del archivo termina con tar.gz
, y este el valor
está asociado con el formato gztar
en el registro de formato para
desempaquetar.
$ 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
Espacio del sistema de archivos¶
Puede ser útil examinar el sistema de archivos local para ver cuánto espacio
hay disponible antes de realizar una operación de larga duración que puede
agota ese espacio. disk_usage()
devuelve una tupla con el espacio total,
la cantidad que se está utilizando actualmente y la cantidad que queda libre.
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))
Los valores devueltos por disk_usage()
son el número de bytes, por lo que
el programa de ejemplo los convierte en unidades más legibles antes de
imprimirlos.
$ 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
Ver también
- Documentación de la biblioteca estándar para shutil
- Compresión y archivo de datos – Módulos para tratar con formatos de archivo y compresión.