使用 tarfile (Python) 仅压缩给定目录中的文件
Compressing only the files inside a given directory using 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/
with src = 'updates/package1'
and dst = 'compressed'
我希望生成的存档将
- 放在
dst
里面(这个有效)
- 包含
file1
和 file2
关于我期待的第二点
./
|---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
虽然解决方案可能真的很微不足道,但我似乎无法弄清楚。我什至在 src
(如果是目录)中尝试 chdir
-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
设置为空字符串。因为它会省略根目录。
我基本上使用 .replace
来删除基本文件夹路径 arcname
。
with tarfile.open(tar_path, tar_compression) as tar_handle:
for root, dirs, files in os.walk(test_data_path):
for file in files:
tar_handle.add(os.path.join(root, file), arcname=os.path.join(root, file).replace(test_data_path, ""))
我编写了以下脚本,允许我将 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/
with src = 'updates/package1'
and dst = 'compressed'
我希望生成的存档将
- 放在
dst
里面(这个有效) - 包含
file1
和file2
关于我期待的第二点
./
|---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
虽然解决方案可能真的很微不足道,但我似乎无法弄清楚。我什至在 src
(如果是目录)中尝试 chdir
-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
设置为空字符串。因为它会省略根目录。
我基本上使用 .replace
来删除基本文件夹路径 arcname
。
with tarfile.open(tar_path, tar_compression) as tar_handle:
for root, dirs, files in os.walk(test_data_path):
for file in files:
tar_handle.add(os.path.join(root, file), arcname=os.path.join(root, file).replace(test_data_path, ""))