使用 tar 或 python 的 tarfile 模块从命名管道创建 tarball

使用 tar 或 python 的 tarfile 模块从命名管道创建 tarball

我没有意识到这会如此困难。我只是用焦油。我有两部分数据,一个是大量的 pcap 数据有效负载,另一个是 python pickled 文件形式的一些附加元数据。我的目标是创建一个包含这两个文件的 .tar 文件,并使用 XZ 进行压缩。

我希望能够对 tarball 建立索引,以便可以从 .tar.xz 文件中快速提取元数据文件。我使用 PIXZ 进行 xz 压缩,它会自动索引 tar 文件。因为我正在压缩的 pcap 数据太大,所以在压缩之前我不想接触磁盘。我正在使用 tcprewrite 对它进行其他一些更改,但这些并不重要。

我已将所有工具设置为使用命名管道,它很漂亮而且非常快。不幸的问题是 tar 不能与命名管道一起使用。每次我尝试压缩命名管道时,它只会将 /dev/fd/#numbers 写入 tarball 中。我不能只是将 pcap 数据写入磁盘或 /dev/shm 来对其进行 tar,重要的是 pcap 数据在压缩之前不会到达磁盘。

我正在用 python 编写整个实用程序,因此我尝试使用 python 的 tarfile 模块。该文档声称它适用于 FIFO,但是当我使用 tarfile.add() 时,我遇到了同样的问题。我尝试过研究像 zip 这样的替代方案(它有一个用于使用命名管道的 -FI 选项),但我需要对我们现有的基础设施使用 tar。

我尝试了 gnutar 和 bsdtar,但它们都不能与管道一起使用。只要最终结果是一个已编入索引并允许快速访问元数据的 .tar.xz 文件,最终使用什么工具并不重要。

答案1

不要为此感到沮丧...我相信您会设法解决这个问题!

我认为 tar 让你困惑的是,“支持命名管道”意味着它可以识别命名管道并存储它们作为命名管道在存档中,以便您稍后可以再次将它们恢复为命名管道...这并不是您真正想要的。

此外,tar 文件的格式不太适合您正在做的事情,因为描述文件的条目存储在其内容之前,并且文件条目必须包含文件大小,因此除非您事先知道内容的确切大小,很难做到这一点...

这个解决方案(参见 TarFileStdin),它使用 hack 来解决这个问题。它插入文件大小为零的 TarInfo,然后存储文件的内容,最后查找原始 TarInfo 的偏移量并用正确的大小覆盖它......这有点太 hacky,但它应该可以工作......但请继续阅读。


您提到“我希望能够对 tarball 建立索引,以便我可以从 .tar.xz 文件中快速提取元数据文件”,这样看起来更像是一个 ZIP 文件! ZIP 格式首先存储所有文件的内容,然后在 ZIP 末尾存储文件信息和偏移量表。从这个意义上说,它是索引的,就像你提到的那样。列出 ZIP 的内容可以很快完成,因为工具可以轻松地从文件末尾开始找到该文件表。

您可以使用 ZIP 的本机压缩格式,也可以仅使用 ZIP 的“存储”模式(未压缩),然后在其中添加 xyz.pcap.xz 文件。将 *.xz 文件添加到 ZIP 中可以方便地使用外部压缩器,例如并行 xz。

Python 3 的zipfile.ZipFile对象有一个open()方法它允许您仅按名称添加文件并接收可以写入内容的文件对象。

您可以使用该 API 并将shutil.copyfileobj()压缩的 pcap 从命名管道添加到 ZIP 文件:

import shutil
import zipfile

with zipfile.ZipFile('mydata.zip', 'w') as zf:
    with zf.open('xyz.pcap.xz', 'w') as outputf:
        with open('/path/to/namedpipe', 'r') as inputf:
            shutil.copyfileobj(inputf, outputf)
    zf.write('metadata.pickle')  # from local directory

此代码片段假设您正在将已 xz 压缩的 pcap 数据写入命名管道,并且元数据已序列化到当前目录中名为“metadata.pickle”的文件中。 (当然,您open()也可以使用 ZipFile 将 pickle 元数据直接序列化到 ZIP 文件中的条目中!)

如果你想使用 zipfile 的本机压缩,你可以为 ZipFile 设置默认压缩:

with zipfile.ZipFile('mydata.zip', 'w', zipfile.ZIP_LZMA) as zf:

(默认值为 ZIP_STORED,这意味着不压缩,如果您要在那里传输 xz 压缩的数据,这可能就是您想要的。)

请参阅zip 文件的文档更多细节。较新的 Python 具有更多功能,例如使用 Python 3.5,您实际上可以将 zip 文件写入管道,这样您就可以通过 SSH 将其直接上传到远程主机。


希望这个对你有帮助!如果您确实需要 tarball,请尝试这个答案,但我确实认为使用 Python 3 的 zipfile 解决方案对于您描述的用例来说是更好的方法!因此,如果这种格式可行,我真的会推荐它。

相关内容