如何仅通过Python字符串和不使用临时文件程序性地创建嵌套目录和文件的tar归档?
我想用Python创建一个tar压缩包,并且里面有层级目录结构,文件的内容是用字符串表示的。我看过这个问题,里面介绍了如何把字符串作为文件添加进去,但没有讲怎么添加目录。我想知道怎么在不实际创建目录的情况下,动态地把目录添加到tar压缩包里。
类似于:
archive.tgz:
file1.txt
file2.txt
dir1/
file3.txt
dir2/
file4.txt
3 个回答
1
看一下tar文件格式,这看起来是可以做到的。每个子目录里的文件会用相对路径名来命名,比如说dir1/file3.txt
。
唯一需要注意的是,你必须在放文件之前先定义好每个目录(tar
不会自动创建需要的子目录)。有一个特殊的标志可以用来标识tar文件中的条目是目录,但为了兼容老版本,tar
也接受以/
结尾的文件名来表示目录,所以你可以用同样的方法,把dir1/
作为一个长度为零的字符串的文件添加进去。
2
对之前那个很有帮助的被接受的答案做了一点小改动,这样它在Python 3和Python 2中都能用,并且更接近原问题的例子:
from io import BytesIO
import tarfile
import time
# create and open empty tar file
tar = tarfile.open("test.tgz", "w:gz")
# Add a file
file1_contents = BytesIO("hello 1".encode())
finfo1 = tarfile.TarInfo(name='file1.txt')
finfo1.size = len(file1_contents.getvalue())
finfo1.mtime = time.time()
tar.addfile(tarinfo=finfo1, fileobj=file1_contents)
# create directory in the tar file
dinfo = tarfile.TarInfo(name='dir')
dinfo.type = tarfile.DIRTYPE
dinfo.mode = 0o755
dinfo.mtime = time.time()
tar.addfile(tarinfo=dinfo)
# add a file to the new directory in the tar file
file2_contents = BytesIO("hello 2".encode())
finfo2 = tarfile.TarInfo(name='dir/file2.txt')
finfo2.size = len(file2_contents.getvalue())
finfo2.mtime = time.time()
tar.addfile(tarinfo=finfo2, fileobj=file2_contents)
tar.close()
具体来说,我更新了八进制的写法,参考了PEP 3127 -- 整数字面量支持和语法,改用了BytesIO from io
,用getvalue
替代了buf
,并且用open
替代了TarFile
,这样可以像例子中那样显示压缩后的输出。(使用上下文管理器的方式(with ... as tar:
)在Python 2和Python 3中都能用,但我在Python 2的环境中复制粘贴时遇到问题,所以没有改这个。)在Python 2.7.15+和Python 3.7.3上测试过。
11
在这个问题的例子基础上,你可以这样做:
import tarfile
import StringIO
import time
tar = tarfile.TarFile("test.tar", "w")
string = StringIO.StringIO()
string.write("hello")
string.seek(0)
info = tarfile.TarInfo(name='dir')
info.type = tarfile.DIRTYPE
info.mode = 0755
info.mtime = time.time()
tar.addfile(tarinfo=info)
info = tarfile.TarInfo(name='dir/foo')
info.size=len(string.buf)
info.mtime = time.time()
tar.addfile(tarinfo=info, fileobj=string)
tar.close()
要注意mode
属性,因为默认值可能不包括目录所有者的执行权限,而这些权限是进入目录和获取其内容所必需的。