假设有一个巨大的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
gztool
chunk.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 个字节为零,但它们不占用磁盘空间。如果没有seek
indd
命令,零将全部写入磁盘,这对于 也有效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?