是否可以广度优先搜索 .tar.gz 文件?

是否可以广度优先搜索 .tar.gz 文件?

我要下载部分一个大的 (199GB) .tar.gz 文件这里。首先,我使用以下命令列出 .tar.gz 文件中的所有文件:

wget -qO- https://www.cs.cornell.edu/projects/megadepth/dataset/Megadepth_v1/MegaDepth_v1.tar.gz | tar -tz

接下来,我尝试使用以下命令下载 .tar.gz 中文件夹的内容:

wget -qO- https://www.cs.cornell.edu/projects/megadepth/dataset/Megadepth_v1/MegaDepth_v1.tar.gz | tar -xz phoenix/S6/zl548/MegaDepth_v1/0000

但是,这花费的时间太长,因为该tar命令会深度优先并递归地搜索下面的每个文件夹phoenix/S6/zl548/MegaDepth_v1。我只对文件夹的内容感兴趣phoenix/S6/zl548/MegaDepth_v1/0000。有没有办法下载该文件夹的内容,而无需搜索其他文件夹的子文件夹,例如

phoenix/S6/zl548/MegaDepth_v1/0162
phoenix/S6/zl548/MegaDepth_v1/0001
phoenix/S6/zl548/MegaDepth_v1/0132

换句话说,有没有更快的方法来下载文件夹的内容phoenix/S6/zl548/MegaDepth_v1/0000


上述命令的一些参考:

如何从 tar.gz 中提取特定文件

如何下载存档并解压而不将存档保存到磁盘?

https://stackoverflow.com/q/2700306/13809128

答案1

tar写入文件头,然后写入文件内容,然后写入下一个文件头,下一个文件内容,依此类推。

条目没有关联的顺序,您可以想到的唯一优化是跳过文件的内容,直接查找下一个标头。为此,您需要有一个可查找的文件。

但是您的内容.gz已被压缩,因此您没有可靠的方法可以跳到下一个条目,这意味着您将必须读取(下载)整个文件以获取内容。这就是答案:不,您无法避免阅读/下载整个文件。

因此,由于无论如何您都必须完全下载它,因此您最好只下载一次,然后解决本地文件系统中的所有问题。

答案2

因为 tar 命令深度优先且递归地搜索......

嗯,实际上并非如此。事实并非如此搜索 根本不,而只是读取存档,查看它遇到的每个文件,看看它们是否匹配它想要的内容。 (您确实获得了深度优先的行为,因为这是遍历目录树的自然顺序,也是文件添加到存档中的顺序。)

这是因为 tar 存档没有索引,因此不可搜索。名称“tar”代表“磁带存档”,使用磁带的通常模式是仅读取或写入单个流,而不进行查找。该格式是针对该上下文而设计的,可能不是最适合您的用例的格式。

我找不到很好的引用,但它在一些 答案在网站上以及维基百科

答案3

每次执行时wget,您都在尝试下载整个 tar 文件!您可能已经多次下载“初始内容”,并通过将输出发送到 stdout 将其丢弃!

相反,“更快”的方法是将其下载一次到当前目录中的 ./MegaDepth_v1.tar.gz 并在那里解压缩。

wget -q -O MegaDepth_v1.tar.gz  https://www.cs.cornell.edu/projects/megadepth/dataset/Megadepth_v1/MegaDepth_v1.tar.gz  
tar -xz -f MegaDepth_v1.tar.gz phoenix/S6/zl548/MegaDepth_v1/0000  

获得必要的文件后,您可以删除下载的 tar 文件。

更新:原始文件的大小似乎约为 200 GB。下载本身会占用大量的时间和空间。提取将花费额外的时间。没有赢, 在这种情况下!
您可能需要联系 MegaDepth 团队并要求他们提供单独的目录访问权限,否则速度总是很慢。

在这里,wget无法跳过不需要的内容,并且始终会从头到尾下载整个 tar 文件。此外,(如用户 ilkkach 的回答中所述)tar无法跳过(或查找)stdout 流。

答案4

分析

我同意其他答案,说没有办法tar寻找压缩档案。要找到您要查找的文件,该工具需要从头开始处理存档,而不是跳过任何内容。

然而,对于 GNU,tar您不一定需要将其处理到底。创建存档时请考虑以下场景:

假设您更改文件blues,然后将更改后的版本附加到collection.tar. [...],原件blues在档案中collection.tar。如果更改文件并将新版本的文件附加到存档中,则存档中将有两个副本。当您提取存档时,将首先提取文件的旧版本,然后在提取时替换为新版本。

来源

这意味着,在提取特定文件时,tar即使在提取文件后也会继续处理存档,因为存档中可能稍后有另一个副本。

但是之后:

blues如果您希望从存档中提取文件的第一次出现,请使用--occurrence选项

(同上)

如果您确定您要查找的文件在存档中仅出现过一次,请使用tar --occurrencetar将在解压文件后停止。然后你的wget将由于 中止SIGPIPE,它不会白白下载档案的其余部分。


用途有限

笔记这对你来说并不是很有用精确的案例因为phoenix/S6/zl548/MegaDepth_v1/0000是一个目录(对吗?)。使用--occurrence,提取目录时tar不会提前停止,除非遇到该目录的另一个条目本身。原因是:phoenix/S6/zl548/MegaDepth_v1/0000/foo档案的最后总是有一个唯一的。在tar结束之前,无法确定目录及其所有内容是否完整。

不过,如果你想要一个或几个非目录,如果您知道路径并且知道存档中每个路径只有一个实例,则将--occurrence允许您根据需要下载尽可能少的存档。如果您很幸运并且文件恰好位于存档的开头附近,那么--occurrence将会产生显着的差异。

也许这个答案不会对你有太大帮助。适用于可以提供以下列表的用户非目录


除非…

如果您保存了输出wget -qO- … | tar -tz(当您很可能下载并处理整个存档并将其丢弃时),您现在可以提供以下列表非目录(可能使用--files-from=--verbatim-files-from;如果列表对于单个命令行来说太长,则特别有用)。在这种情况下--occurrence可能适合你。此外,保存的输出tar -t将允许您确认您所查找的每个非目录在存档中仅出现一次,因此您知道--occurrence不会让您错过更新的版本。

上面的假设MegaDepth_v1.tar.gz在服务器上没有改变。一般来说(如果存档可能已更改)您保存的输出tar -t可能不再有效。

假设您可以创建要提取的非目录列表。该清单必须不是明确指定任何目录,否则--occurrence不会帮助您。仍然tar会创建必要的目录,但只是为了将非目录放入其中,而不是因为它会真正从存档中提取目录。换句话说:目录本身的存档成员并不重要。这意味着将创建目录,但类似的选项--preserve-permissions不适用于它们。


概念证明

我使用了您的第一个命令(带有 的命令tar -t)并发现这phoenix/S6/zl548/MegaDepth_v1/0162/dense0/depths/16384199365_2b34b42cf4_b.h5是靠近存档开头的非目录。该管道:

wget -qO- https://www.cs.cornell.edu/projects/megadepth/dataset/Megadepth_v1/MegaDepth_v1.tar.gz \
| tar -xvz phoenix/S6/zl548/MegaDepth_v1/0162/dense0/depths/16384199365_2b34b42cf4_b.h5

提取文件并继续(我可以Ctrl+ c);但这一个:

wget -qO- https://www.cs.cornell.edu/projects/megadepth/dataset/Megadepth_v1/MegaDepth_v1.tar.gz \
| tar --occurrence -xvz phoenix/S6/zl548/MegaDepth_v1/0162/dense0/depths/16384199365_2b34b42cf4_b.h5

提取文件并自动终止。

相关内容