使用tarfile(Python)仅压缩给定目录中的文件

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了使用tarfile(Python)仅压缩给定目录中的文件相关的知识,希望对你有一定的参考价值。

我编写了以下脚本,允许我压缩src(可以是单个文件或目录)来定位'dst':

#!/usr/bin/env python2

import tarfile
from ntpath import basename, dirname
from os import path, listdir, makedirs, chdir
import errno
import sys

class Archivator:
    @staticmethod
    def compress(src='input/test', dst='output'):
        # if not path.isfile(src_file):
        #     print('Expecting absolute path to file (not directory) as "src". If "src" does contain a file, the file does not exist')
        #     return False

        if not path.isdir(dst):
            return False
            # try:
            #     makedirs(dst_dir)
            # except OSError as err:
            #     if err.errno != errno.EEXIST:
            #         return False

        filename = basename(src) if path.isdir(src) else src
        tar_file = dst + '/' + filename + '.tar.gz'
        print(tar_file)
        print(src)
        with tarfile.open(tar_file, 'w:gz') as tar:
            print('Creating archive "' + tar_file + '"')
            # chdir(dirname(dst_dir))
            recr = path.isdir(src)
            if recr:
                print('Source is a directory. Will compress all contents using recursion')
            tar.add(src, recursive=recr)

        return True


if __name__ == '__main__':
    import argparse

    parser = argparse.ArgumentParser(description='Uses tar to compress file')
    parser.add_argument('-src', '--source', type=str,
                        help='Absolute path to file (not directory) that will be compressed')
    parser.add_argument('-dst', '--destination', type=str, default='output/',
                        help='Path to output directory. Create archive inside the directory will have the same name as value of "--src" argument')

    # Generate configuration
    config = parser.parse_args()

    Archivator.compress(config.source, config.destination)

对于单个文件,我到目前为止还没有遇到过问题。然而,当src(作为目录)的压缩确实起作用(递归和所有)时,我注意到一个非常恼人的问题,即完整的目录结构在tar.gz存档中被复制。

例:

假设我有以下文件结构:

./
 |---compression.py (script above)
 |
 |---updates/
 |       |
 |       |---package1/
 |               |
 |               |---file1
 |               |---file2
 |               |---dir/
 |                     |
 |                     |---file3
 |
 |---compressed/

src = 'updates/package1'dst = 'compressed'我期待由此产生的档案

  • 放在dst内(这是有效的)
  • 包含file1file2

关于我期望的第二点

./
 |---compression.py (script above)
 |
 |---updates/
 |       |
 |       |---package1/
 |               |
 |               |---file1
 |               |---file2
 |               |---dir/
 |                    |
 |                    |---file3
 |
 |---compressed/
          |
          |---package1.tar.gz
                 |
                 |---file1
                 |---file2
                 |---dir/
                      |
                      |---file3

但我得到了

./
 |---compression.py (script above)
 |
 |---updates/
 |       |
 |       |---package1/
 |               |
 |               |---file1
 |               |---file2
 |               |---dir/
 |                    |
 |                    |---file3
 |
 |---compressed/
         |
         |---package1.tar.gz
                 |
                 |---updates/
                        |
                        |---package1/
                                |
                                |---file1
                                |---file2
                                |---dir/
                                     |
                                     |---file3

虽然解决方案可能非常简单,但我似乎无法弄明白。我甚至在chdir(如果是目录)中尝试过src-ing但它没有用。我的一些实验甚至导致OSError(由于缺少预期存在的目录)和存档损坏。

答案

首先,你错误地使用参数recursive

根据tarfile的官方文件:

def add(self, name, arcname=None, recursive=True, exclude=None):
    """Add the file `name' to the archive. `name' may be any type of file
       (directory, fifo, symbolic link, etc.). If given, `arcname'
       specifies an alternative name for the file in the archive.
       Directories are added recursively by default. This can be avoided by
       setting `recursive' to False. `exclude' is a function that should
       return True for each filename to be excluded.
    """

您可以使用arcname在存档中指定备用名称。并且recursive用于控制是否递归创建目录。

tarfile可以直接添加目录。

回到你的问题,你可以手动添加每个文件并指定他们的arcname。例如,tar.add("updates/package1/file1", "file1")

更新

或者您可以将arcname设置为空字符串。因为它会省略根目录。

以上是关于使用tarfile(Python)仅压缩给定目录中的文件的主要内容,如果未能解决你的问题,请参考以下文章

如何在不添加目录层次结构的情况下使用 Python 将文件添加到 tarfile?

Python中使用tarfile压缩解压tar归档文件示例(最新+全面=强烈推荐! ! !)

tarfile/zipfile/shutil

python常用标准库(压缩包模块zipfile和tarfile)

使用 Python 从仅具有基本名称的 tarfile 中提取文件

shutilzipfile,tarfile