9.5. tarfile — 访问 tar 压缩文件 | 数据压缩和归档 |《python 3 标准库实例教程》| python 技术论坛-380玩彩网官网入口

未匹配的标注

目的:tar 存档访问。

tarfile 模块提供对 unix tar 存档的读写访问,包括压缩文件。除了posix 标准之外,还支持几种 gnu tar 扩展。还提供处理 unix 特殊文件类型,如硬链接和软链接,以及设备节点。

注意

虽然 tarfile 实现了 unix 格式,但它也可用于在 microsoft windows 下创建和读取 tar 存档。

测试 tar 文件

is_tarfile() 函数返回一个布尔值,指示作为参数传递的文件名是否指向有效的 tar 存档。

tarfile_is_tarfile.py

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))

如果文件不存在,is_tarfile() 会引发一个 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'

从tar压缩文档中读取元数据 (metadata)

直接使用 tarfile 类来操作一个tar压缩文件。这个类不仅可用来读取数据,而且可用来添加文件到压缩文件中。

使用getnames()来读取压缩文件中所有文件的文件名。

tarfile_getnames.py

import tarfile
with tarfile.open('example.tar', 'r') as t:
    print(t.getnames())

该函数的返回一个字符串列表,包含了所有所含文件的文件名。

$ python3 tarfile_getnames.py
['index.rst', 'readme.txt']

除了文件名,其他元数据信息可以通过使用tarinfo类的实例来获取。

tarfile_getmembers.py

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()

通过 getmembers() 和 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

如果一个所含文件的文件名已知,可使用getmember()函数获取其所对应的 tarinfo对象。

tarfile_getmember.py

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))

如果文件名所对应的文件不存在压缩文件中,函数 getmember() 会抛出一个 keyerror异常。

$ python3 tarfile_getmember.py
readme.txt is 75 bytes
error: did not find notthere.txt in tar archive

从归档中提取文件

如果需要在程序中的某个归档成员中访问数据,可使用 extractfile() 方法,并把归档成员名作为参数传入。

tarfile_extractfile.py

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'))

返回值是一个类似文件的对象,从该对象中可以读取归档成员的内容。

$ 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

若想对归档行解包操作,并将文件写入文件系统内,可以使用 extract() 或 extractall() 取代之前的方法。

tarfile_extract.py

import tarfile
import os
os.mkdir('outdir')
with tarfile.open('example.tar', 'r') as t:
    t.extract('readme.txt', 'outdir')
print(os.listdir('outdir'))

归档中的成员被从归档中读取并写入文件系统,这一过程开始于由参数中命名的那个路径之内。

$ python3 tarfile_extract.py
['readme.txt']

标准库文档中有一个注释提到 extractall() 方法的安全性强于 extract() ,尤其是在处理不能回滚读取较早时间输入部分的流式数据的情况下,所以前者应当更广泛地应用。

tarfile_extractall.py

import tarfile
import os
os.mkdir('outdir')
with tarfile.open('example.tar', 'r') as t:
    t.extractall('outdir')
print(os.listdir('outdir'))

extractall() 的第一个参数是文件被写入路径的名称。

$ python3 tarfile_extractall.py
['readme.txt', 'index.rst']

若需从归档中提取特定的文件,可将需提取的文件名或者 tarinfo 元数据容器作为参数传递给 extractall()

tarfile_extractall_members.py

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'))

在提供了 members 列表的情况下,只有列表中提名的文件会被提取。

$ python3 tarfile_extractall_members.py
['readme.txt']

创建一个新的归档文件

使用带'w'模式的tarfile 来创建一个新的归档文件。

tarfile_add.py

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)

已有的文件会被清除,同时创立一个新的归档文件。使用 add() 函数来添加新成员到新建的归档文件中。

$ python3 tarfile_add.py
creating archive
adding readme.txt
contents:
readme.txt

以新名字来归档成员

当添加新文件到归档文件时,可以使用不同的文件名。这个可通过构造一个带有arcnametarinfo对象,并将其传入addfile()函数来实现。

tarfile_addfile.py

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)

该归档只含有一个重命名的文件:

$ python3 tarfile_addfile.py
creating archive
adding readme.txt as renamed.txt
contents:
renamed.txt

从文件以外的源来写入数据

有时候,我们需要直接从内存中将数据写进压缩包,而不是先将数据写入文件,再将文件添加进压缩包。你可以使用 addfile() 来从类似于打开文件的句柄添加数据来返回字节。

tarfile_addfile_string.py

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'))

通过首先构造 tarinfo 对象, 可以为压缩包成员指定你想要的任意名称。在设置了其大小之后,使用 addfile() 和 bytesio 缓冲区作为数据源将数据写进压缩包中。

$ python3 tarfile_addfile_string.py
contents:
made_up_file.txt
this is the data to write to the archive.

添加新成员

除了创建新的归档文件,还可以通过设置模式参数为'a'来添加新文件到已有的归档文件。

tarfile_append.py

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()])

最终的归档文件包含了两个成员:

$ python3 tarfile_append.py
creating archive
contents:
['readme.txt']
adding index.rst
contents:
['readme.txt', 'index.rst']

处理压缩的归档文件

除了正常的tar 归档文件,tarfile模块还可处理通过gzip或bzip2协议压缩的归档文件。要打开一个压缩的归档文件,根据不同的压缩协议,传入 ":gz" 或 ":bz2"模式参数到 open() 函数。

tarfile_compression.py

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()
    ])

如果使用"r:*" 模式读取一个归档文件时,tarfile会自动识别压缩方法。

$ 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']

参考

  •  -- tar格式的文档及其扩展
  •  -- 类似的 zip 文档处理
  •  -- 读写gnu zip 压缩
  •  -- bzip2 压缩方法

本文章首发在 380玩彩网官网入口 网站上。

本译文仅用于学习和交流目的,转载请务必注明文章译者、出处、和本文链接
我们的翻译工作遵照 cc 协议,如果我们的工作有侵犯到您的权益,请及时联系380玩彩网官网入口。

原文地址:https://learnku.com/docs/pymotw/tarfile-...

译文地址:https://learnku.com/docs/pymotw/tarfile-...

上一篇 下一篇
讨论数量: 0



暂无话题~
网站地图