使用Python透明挂载tar.gz归档文件
如何用Python透明地挂载一个tar.gz压缩包?
我有一个tar.gz格式的压缩包,里面的内容需要被一个外部程序读取。这些内容只需要暂时用一下。我可以把它解压到一个临时文件夹,然后让外部程序去那个文件夹读取。不过,这个压缩包可能很大(解压后超过1GB),所以解压出来会占用很多磁盘空间。我的服务器在硬盘性能上比较弱,不能随便浪费空间,但它有很多内存和CPU资源。
所以我想尝试不完全解压就透明地挂载这个压缩包。我发现了一个叫archivemount的工具,它似乎正好能满足我的需求。有没有办法用纯Python实现archivemount的功能?请不要提到使用subprocess.call的解决方案。这个方法应该能在64位的Linux上运行。
我觉得可以聪明地使用tarfile来访问压缩包的内容,然后用fusepy来创建一个用户空间的文件系统,暴露出压缩包的内容。有没有人已经把这些部分组合在一起了?有什么想法吗?
如果你觉得这个主意不好,请发表相关评论。如果你知道更好的方法,请留言。
1 个回答
在我的ratarmount模块的0.3.1版本中,你可以使用这个模块,或者查看它的源代码来在Python中挂载一个.tar.gz文件。gzip的查找支持来自于一个叫indexed_gzip的依赖库。Ratarmount本身是基于tarindexer,这个库的思路是使用tarfile来获取偏移量,然后直接跳到那个位置。不过,ratarmount在此基础上增加了一个FUSE层,以及其他一些提高可用性和性能的功能。
你可以从PyPI安装ratarmount:
pip3 install --user ratarmount
然后可以直接在Python中调用它的命令行接口,方法如下:
import ratarmount
ratarmount.cli( [ '--help' ] )
ratarmount.cli( [ pathToTar, pathToMountPoint ] )
这个模块的核心正如你所猜测的那样,是tarfile,它用于遍历所有的TarInfo对象,并创建一个包含文件路径、偏移量和大小的列表。这个列表可以用来直接跳到原始tar文件中的偏移量,然后简单地读取接下来的字节。这是可行的,因为TAR格式本身就很简单。
下面是未经优化的非常基础的核心思路:
import sys
import tarfile
from indexed_gzip import IndexedGzipFile
targzfile = sys.argv[1]
filetoprint = sys.argv[2]
index = {} # path : ( offset, size )
file = IndexedGzipFile( targzfile )
for tarinfo in tarfile.open( fileobj = file, mode = 'r|' ):
index[tarinfo.name] = ( tarinfo.offset_data, tarinfo.size )
# at this point you could save or load the index for faster consecutive file seeks
file.seek( index[filetoprint][0] )
sys.stdout.buffer.write( file.read( index[filetoprint][1] ) )
上面的例子经过测试可以正常工作:
wget -O- 'https://ftp.mozilla.org/pub/firefox/releases/70.0/linux-x86_64/en-US/firefox-70.0.tar.bz2' | bzip2 -d -c | gzip > firefox.tgz
python3 minimal-example.py firefox.tgz firefox/updater.ini