使用偏移量读取部分下载的 gzip

使用偏移量读取部分下载的 gzip

假设有一个巨大的db.sql.gz可用大小 100GBhttps://example.com/db/backups/db.sql.gz并且服务器支持范围请求

所以我没有下载整个文件,而是下载了y字节(比方说 1024 字节),偏移量为x字节(假设 1000 字节)如下所示。

curl -r 1000-2024 https://example.com/db/backups/db.sql.gz

通过上面的命令,我能够下载 gzip 压缩文件的部分内容,现在我的问题是如何读取该部分内容?

我尝试过gunzip -c db.sql.gz | dd ibs=1024 skip=0 count=1 > o.sql,但这给出了一个错误

gzip:dbrange.sql.gz:不是 gzip 格式

该错误是可以接受的,因为我猜测文件顶部可能有描述编码的标头块。


我注意到,如果我下载没有偏移量的文件,我可以使用gunzip管道读取文件。

curl -r 0-2024 https://example.com/db/backups/db.sql.gz

答案1

只是FWIW,gzip 可以随机访问,如果以前指数文件已创建...

我开发了一个命令行工具,如果提供了索引,它可以快速且(几乎)随机地访问 gzip(如果未提供,则会自动创建):

https://github.com/circulosmeos/gztool

gztool可以用来访问原始 gzip 文件的块,如果这些块是在索引指向的特定字节点检索的(当然是 -1 字节,因为 gzip 是位流,而不是字节),或者更好,在他们之后。

例如如果索引点开始gztool -ll index.gzi提供此数据)以压缩字节1508611gzip 文件的一部分,之后我们需要 1M 压缩字节:

$ curl -r 1508610-2508611 https://example.com/db/backups/db.sql.gz > chunk.gz
  • 请注意,chunk.gz只会占用磁盘上的块大小!
  • 另请注意,它是不是有效的 gzip 文件,因为它不完整。
  • 还请考虑到我们已经从所需的索引点位置减 1 个字节进行检索。

现在,还必须检索完整的索引(以前仅创建一次:例如gztool -i *.gz为所有已 gzip 压缩的文件创建索引,或者gztool -c *压缩并创建索引)。请注意,索引约为 gzip 大小的 0.3%(如果gztool压缩数据本身,则索引会小得多)。

$ curl https://example.com/db/backups/db.sql.gzi -o chunk.gzi

现在提取可以通过格子工具。压缩 1508610 的相应未压缩字节(或传递该字节的字节)必须已知,但索引可以使用gztool -ll.看例子在这里。假设它是字节 9009009。或者我们想要的未压缩字节只是传递到 chunk.gz 中包含的相应第一个索引点。让我们再次假设在这种情况下该字节也将是 9009009。

$ gztool -n 1508610 -b 9009009 chunk.gz > extracted_chunk.sql

gztoolchunk.gz当文件结束时将停止提取数据。

也许很棘手,但可以在不改变压缩方法或已经压缩的文件的情况下运行。但需要为它们创建索引。


笔记:不使用参数进行提取的另一种方法-n是将 gzip 文件填充为零:在示例中这是通过dd命令完成的第一个curl用于检索chunk.gz文件,因此:

$ dd if=/dev/zero of=chunk.gz seek=1508609 bs=1 count=0
$ curl -r 1508610-2508611 https://example.com/db/backups/db.sql.gz >> chunk.gz
$ curl https://example.com/db/backups/db.sql.gzi -o chunk.gzi

这样,文件的前 1508609 个字节为零,但它们不占用磁盘空间。如果没有seekindd命令,零将全部写入磁盘,这对于 也有效gzip,但这样我们就不会占用磁盘上不必要的空间。那么,gztool命令就不需要该-n参数了。不需要清零的数据,因为当索引存在时,gztool将使用它跳转到未压缩的 9009009 字节位置之前的索引点,因此所有先前的数据都将被忽略:

$ gztool -b 9009009 chunk.gz > extracted_chunk.sql

答案2

gzip不生成块压缩文件(请参阅RFC对于血淋淋的细节),所以它本身不适合随机访问。您可以开始从流中读取数据并随时停止,这就是您的curl -r 0-2024示例有效的原因,但您无法在中间获取流,除非您有一个补充文件来提供丢失的数据(例如索引文件)由...制作gztool)。

为了实现您想要做的事情,您需要使用某种类型的块压缩;例如 bgzip(它生成可以通过 plain 解压缩的文件gzip)或bzip2,并在接收端做一些工作以确定块边界所在的位置。 Peter Cock 就这个主题写了一些有趣的文章:BGZF - 受阻、更大、更好的 GZIP!,随机访问BZIP2?

相关内容