tarfile — Acceso a archivos Tar¶
Propósito: | Acceso a archivos Tar |
---|
El módulo tarfile
proporciona acceso de lectura y escritura a archivos de
Unix tar, incluyendo archivos comprimidos. Además de los estándares POSIX,
varias extensiones de tar de GNU son compatibles. Tipos especiales de archivos
Unix, como los enlaces duros y blandos, y los nodos de dispositivos también son
manejados.
Nota
Aunque tarfile
implementa un formato Unix, puede usarse también para
crear y leer archivos tar en Microsoft Windows.
Archivos Tar de prueba¶
La función is_tarfile()
devuelve un valor booleano que indica si o no, el
nombre de archivo pasado como argumento hace referencia a un archivo tar
válido.
import tarfile
for filename in ['README.txt', 'example.tar',
'bad_example.tar', 'notthere.tar']:
try:
print('{:>15} {}'.format(filename, tarfile.is_tarfile(
filename)))
except IOError as err:
print('{:>15} {}'.format(filename, err))
Si el archivo no existe, is_tarfile()
levanta el IOError
.
$ python3 tarfile_is_tarfile.py
README.txt False
example.tar True
bad_example.tar False
notthere.tar [Errno 2] No such file or directory:
'notthere.tar'
Leer de metadatos de un archivo¶
Usa la clase TarFile
para trabajar directamente con un archivo tar. Ésta
admite métodos para leer datos sobre archivos existentes, así como modificar
los archivos agregando archivos adicionales.
Para leer los nombres de los archivos en un archivo existente, usa
getnames()
.
import tarfile
with tarfile.open('example.tar', 'r') as t:
print(t.getnames())
El valor de retorno es una lista de cadenas con los nombres del contenido del archivo.
$ python3 tarfile_getnames.py
['index.rst', 'README.txt']
Además de los nombres, los metadatos sobre los miembros del archivo están
disponibles como instancias de objetos TarInfo
.
import tarfile
import time
with tarfile.open('example.tar', 'r') as t:
for member_info in t.getmembers():
print(member_info.name)
print(' Modified:', time.ctime(member_info.mtime))
print(' Mode :', oct(member_info.mode))
print(' Type :', member_info.type)
print(' Size :', member_info.size, 'bytes')
print()
Cargue los metadatos a través de getmembers()
y getmember()
.
$ python3 tarfile_getmembers.py
index.rst
Modified: Fri Aug 19 16:27:54 2016
Mode : 0o644
Type : b'0'
Size : 9878 bytes
README.txt
Modified: Fri Aug 19 16:27:54 2016
Mode : 0o644
Type : b'0'
Size : 75 bytes
Si el nombre del miembro del archivo es conocido de antemano, su objeto
TarInfo
se puede recuperar con getmember()
.
import tarfile
import time
with tarfile.open('example.tar', 'r') as t:
for filename in ['README.txt', 'notthere.txt']:
try:
info = t.getmember(filename)
except KeyError:
print('ERROR: Did not find {} in tar archive'.format(
filename))
else:
print('{} is {:d} bytes'.format(
info.name, info.size))
Si el miembro del archivo no está presente, getmember()
levanta un
KeyError
.
$ python3 tarfile_getmember.py
README.txt is 75 bytes
ERROR: Did not find notthere.txt in tar archive
Extraer archivos de un archivo¶
Para acceder a los datos de un miembro del archivo dentro de un programa, usa
el método extractfile()
, pasando el nombre del miembro.
import tarfile
with tarfile.open('example.tar', 'r') as t:
for filename in ['README.txt', 'notthere.txt']:
try:
f = t.extractfile(filename)
except KeyError:
print('ERROR: Did not find {} in tar archive'.format(
filename))
else:
print(filename, ':')
print(f.read().decode('utf-8'))
El valor de retorno es un objeto similar a un archivo desde el cual se pueden leer los contenidos del miembro del archivo.
$ python3 tarfile_extractfile.py
README.txt :
The examples for the tarfile module use this file and
example.tar as data.
ERROR: Did not find notthere.txt in tar archive
Para descomprimir el archivo y escribir los archivos en el sistema de archivos,
usa extract()
o extractall()
en su lugar.
import tarfile
import os
os.mkdir('outdir')
with tarfile.open('example.tar', 'r') as t:
t.extract('README.txt', 'outdir')
print(os.listdir('outdir'))
El miembro o miembros se leen del archivo y se escriben en el sistema de archivos, comenzando en el directorio nombrado en los argumentos.
$ python3 tarfile_extract.py
['README.txt']
La documentación de la biblioteca estándar incluye una nota que indica que
extractall()
es más segura que extract()
, especialmente para trabajar
con la transmisión de datos donde rebobinar para leer una parte anterior de la
entrada no es posible, y debe utilizarse en la mayoría de los casos.
import tarfile
import os
os.mkdir('outdir')
with tarfile.open('example.tar', 'r') as t:
t.extractall('outdir')
print(os.listdir('outdir'))
Con extractall()
, el primer argumento es el nombre del directorio donde se
deben escribir los archivos.
$ python3 tarfile_extractall.py
['README.txt', 'index.rst']
Para extraer archivos específicos del archivo, pasa sus nombres o los
contenedores de metadatos TarInfo
a extractall()
.
import tarfile
import os
os.mkdir('outdir')
with tarfile.open('example.tar', 'r') as t:
t.extractall('outdir',
members=[t.getmember('README.txt')],
)
print(os.listdir('outdir'))
Cuando se proporciona una lista de members
, solo se extraen los archivos
nombrados.
$ python3 tarfile_extractall_members.py
['README.txt']
Crear Nuevos Archivos¶
Para crear un nuevo archivo, abre el TarFile
con un modo de 'w'
.
import tarfile
print('creating archive')
with tarfile.open('tarfile_add.tar', mode='w') as out:
print('adding README.txt')
out.add('README.txt')
print()
print('Contents:')
with tarfile.open('tarfile_add.tar', mode='r') as t:
for member_info in t.getmembers():
print(member_info.name)
Cualquier archivo existente se trunca y se inicia un nuevo archivo. Para añadir
archivos, usa el método add()
.
$ python3 tarfile_add.py
creating archive
adding README.txt
Contents:
README.txt
Usar nombres alternativos de miembros de archivo¶
Es posible agregar un archivo a un archivo usando un nombre diferente al nombre
de archivo original mediante la construcción de un objeto TarInfo
con una
arcname
alternativo y pasándolo a addfile()
.
import tarfile
print('creating archive')
with tarfile.open('tarfile_addfile.tar', mode='w') as out:
print('adding README.txt as RENAMED.txt')
info = out.gettarinfo('README.txt', arcname='RENAMED.txt')
out.addfile(info)
print()
print('Contents:')
with tarfile.open('tarfile_addfile.tar', mode='r') as t:
for member_info in t.getmembers():
print(member_info.name)
El archivo incluye solo el nombre de archivo cambiado:
$ python3 tarfile_addfile.py
creating archive
adding README.txt as RENAMED.txt
Contents:
RENAMED.txt
Escribir datos de fuentes que no sean archivos¶
A veces es necesario escribir datos en un archivo directamente desde la
memoria. En lugar de escribir los datos en un archivo, y a continuación,
agregar ese archivo al archivo, puedes usar addfile()
para agregar datos de
un manejador de archivo abierto como un archivo que devuelve bytes.
import io
import tarfile
text = 'This is the data to write to the archive.'
data = text.encode('utf-8')
with tarfile.open('addfile_string.tar', mode='w') as out:
info = tarfile.TarInfo('made_up_file.txt')
info.size = len(data)
out.addfile(info, io.BytesIO(data))
print('Contents:')
with tarfile.open('addfile_string.tar', mode='r') as t:
for member_info in t.getmembers():
print(member_info.name)
f = t.extractfile(member_info)
print(f.read().decode('utf-8'))
Al construir primero un objeto TarInfo
, le puedes dar cualquier nombre
deseado al miembro del archivo. Después de configurar el tamaño, los datos son
escritos en el archivo usando addfile()
y un búfer BytesIO
como
fuente de los datos.
$ python3 tarfile_addfile_string.py
Contents:
made_up_file.txt
This is the data to write to the archive.
Anexar a Archivos¶
Además de crear nuevos archivos, es posible adjuntar a un archivo existente
usando el modo 'a'
.
import tarfile
print('creating archive')
with tarfile.open('tarfile_append.tar', mode='w') as out:
out.add('README.txt')
print('contents:',)
with tarfile.open('tarfile_append.tar', mode='r') as t:
print([m.name for m in t.getmembers()])
print('adding index.rst')
with tarfile.open('tarfile_append.tar', mode='a') as out:
out.add('index.rst')
print('contents:',)
with tarfile.open('tarfile_append.tar', mode='r') as t:
print([m.name for m in t.getmembers()])
El archivo resultante termina con dos miembros:
$ python3 tarfile_append.py
creating archive
contents:
['README.txt']
adding index.rst
contents:
['README.txt', 'index.rst']
Trabajar con archivos comprimidos¶
Además de los archivos regulares de archivos tar, el módulo tarfile
puede
funcionar con archivos comprimidos a través de los protocolos gzip o bzip2.
Para abrir un archivo comprimido, modifica la cadena de modo pasada a
open()
para que incluya ":gz"
o ":bz2"
, dependiendo del método de
compresión deseado.
import tarfile
import os
fmt = '{:<30} {:<10}'
print(fmt.format('FILENAME', 'SIZE'))
print(fmt.format('README.txt', os.stat('README.txt').st_size))
FILES = [
('tarfile_compression.tar', 'w'),
('tarfile_compression.tar.gz', 'w:gz'),
('tarfile_compression.tar.bz2', 'w:bz2'),
]
for filename, write_mode in FILES:
with tarfile.open(filename, mode=write_mode) as out:
out.add('README.txt')
print(fmt.format(filename, os.stat(filename).st_size),
end=' ')
print([
m.name
for m in tarfile.open(filename, 'r:*').getmembers()
])
Al abrir un archivo existente para leer, especifica "r:*"
para tener que
tarfile
determine automáticamente el método de compresión a usar.
$ python3 tarfile_compression.py
FILENAME SIZE
README.txt 75
tarfile_compression.tar 10240 ['README.txt']
tarfile_compression.tar.gz 213 ['README.txt']
tarfile_compression.tar.bz2 199 ['README.txt']
Ver también
- Documentación de la biblioteca estándar para tarfile
- Manual de GNU tar – Documentación del formato tar, inlcuyendo extensionsiones.
zipfile
– Acceso similar para archivos ZIP.gzip
– Compresión GNU zipbz2
– Compresión bzip2