从tar.gz中提取文件,无需触碰磁盘

5

当前的流程:

  1. 我有一个 tar.gz 文件。(实际上,我有大约 2000 个这样的文件,但这是另外一个故事。)
  2. 我创建一个临时目录,解压 tar.gz 文件,得到100,000个小文件(每个文件大小大约为600字节)。
  3. 针对每个文件,我将它传递给一个处理程序进行处理,将该循环传递给另一个分析程序,并保存结果。

我使用的机器上的临时空间几乎无法同时处理其中一个进程,更不用说默认情况下会发送16个(超线程双四核)。我正在寻找一种在不保存到磁盘的情况下执行此过程的方法。我认为单独使用 tar -xf $file -O <targetname> 来拉取文件的性能惩罚是禁止的,但这可能是我卡住的地方。

有没有什么方法可以做到这一点?

编辑:由于已经有两个人犯了这个错误,我要澄清一下:

  • 每个文件代表一个时间点。
  • 每个文件都是单独处理的。
  • 处理后(在这种情况下是傅里叶分析的变种),每个文件会产生一行输出。
  • 这些输出可以组合起来执行像跨时间的自相关之类的操作。

编辑2:实际代码:

for f in posns/*; do
    ~/data_analysis/intermediate_scattering_function < "$f"
done | ~/data_analysis/complex_autocorrelation.awk limit=1000 > inter_autocorr.txt

未压缩文件的总大小是多少?你有多少内存? - Pablo Mescher
100K个文件 * 4KB最小文件大小 = 400MB。我有16GB,所以16个文件不会有太多问题。 - zebediah49
好的,我本来想告诉你使用ramdisk,但是@Harald Brinkhof已经说了 :) - Pablo Mescher
只需要使用-xf,而不是-xzf吗?标题中提到了.tar.gz,但如果您没有进行压缩,Python的tarfile模块将能够在非流模式下打开文件并查找,从而使随机访问更加高效。 - Charles Duffy
那是一个打字错误,虽然我不反对先解压缩。 - zebediah49
5个回答

7
如果您不关心文件之间的边界,则 tar --to-stdout -xf $file 将实现您想要的功能; 它将依次将归档中每个文件的内容发送到标准输出(stdout)。
假设您使用的是GNU tar,如果您使用bash,则这种情况相当可能。
[更新]
鉴于您确实希望单独处理每个文件的限制,我同意Charles Duffy的看法,即shell脚本是错误的工具。
您可以尝试他的Python建议,或者您可以尝试 Archive::Tar Perl模块。 这两个都允许您在内存中迭代遍历tar文件的内容。

很遗憾,是的;每个目标文件必须单独处理...然后将其输出合并。 - zebediah49
+1 这将节省创建 100000 只猫进程的开销,这是节省了很多开销。 - Paul

4

看起来这个情况下适合的工具可能不是shell脚本。Python有一个tarfile模块,可以在流模式下操作,让您只需通过大型归档文件进行一次处理并处理其文件,同时仍能够区分单个文件(而tar --to-stdout方法则不能)。


将分析代码重写为Python语言,运行时间由数小时缩短至几分钟。 - zebediah49

4
您可以使用tar选项--to-command=cmd为每个文件执行命令。Tar将文件内容重定向到命令的标准输入,并设置一些环境变量,其中包括TAR_FILENAME等有关文件的详细信息。更多详细信息请参见Tar文档
例如:
tar zxf file.tar.gz --to-command='./process.sh'

请注意,OSX默认使用bsdtar,该命令没有这个选项。您可以显式地调用gnutar代替它。

不错!这是我不知道的一个。 :) - Charles Duffy

2

我正在考虑使用tmpfs;但这需要我说服管理员去执行。 - zebediah49

0
tar zxvf <file.tar.gz> <path_to_extract> --to-command=cat

上述命令只会在shell中显示提取文件的内容,不会对磁盘进行任何更改。tar命令应为GNU tar。

示例日志:

$ cat file_a
aaaa
$ cat file_b
bbbb
$ cat file_c
cccc
$ tar zcvf file.tar.gz file_a file_b file_c
file_a
file_b
file_c
$ cd temp
$ ls <== no files in directory
$ tar zxvf ../file.tar.gz file_b --to-command=cat
file_b
bbbb
$ tar zxvf ../file.tar.gz file_a --to-command=cat
file_a
aaaa
$ ls  <== Even after tar extract - no files in directory. So, no changes to disk
$ tar --version
tar (GNU tar) 1.25
...
$

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接