就地解压 gzip 文件

就地解压 gzip 文件

我有一个用 gzip 压缩的大文件(420 GB),我想解压缩它,但我的硬盘没有空间来存储整个压缩文件及其内容。

有没有一种方法可以“在删除它的同时”对其进行解压缩?

如果有帮助的话, gzip -l 说里面只有一个文件(这是一个 tar 文件,我也必须以某种方式将其分离)

提前致谢!

答案1

有没有一种方法可以“在删除它的同时”对其进行解压缩?

这就是你所要求的。但这可能不是您真正想要的。使用风险自负。

如果 420GB 文件存储在具有稀疏文件和打孔支持的文件系统上(例如ext4xfs,但不是ntfs),则可以使用 读取文件并释放读取块fallocate --punch-hole。但是,如果该过程因任何原因被取消,则可能无法恢复,因为剩下的只是半删除、半未压缩的文件。在未先制作源文件的另一个副本的情况下,请勿尝试执行此操作。

非常粗略的概念证明:

# dd if=/dev/urandom bs=1M count=6000 | pigz --fast > urandom.img.gz
6000+0 records in
6000+0 records out
6291456000 bytes (6.3 GB, 5.9 GiB) copied, 52.2806 s, 120 MB/s
# df -h urandom.img.gz 
Filesystem      Size  Used Avail Use% Mounted on
tmpfs           7.9G  6.0G  2.0G  76% /dev/shm

urandom.img.gz文件占用了76%的可用空间,因此无法直接解压缩。将未压缩的结果通过管道传递给我们,md5sum以便我们稍后验证:

# gunzip < urandom.img.gz | md5sum
bc5ed6284fd2d2161296363edaea5a6d  -

打孔时解压缩:(这是非常粗糙的,没有任何错误检查)

total=$(stat --format='%s' urandom.img.gz) # bytes
total=$((1+$total/1024/1024)) # MiB
for ((offset=0; offset < $total; offset++))
do
    # read block
    dd bs=1M skip=$offset count=1 if=urandom.img.gz 2> /dev/null
    # delete (punch-hole) blocks we read
    fallocate --punch-hole --offset="$offset"MiB --length=1MiB urandom.img.gz
done | gunzip > urandom.img

结果:

# ls -alh *
-rw-r--r-- 1 root root 5.9G Jan 31 15:14 urandom.img
-rw-r--r-- 1 root root 5.9G Jan 31 15:14 urandom.img.gz
# du -hcs *
5.9G    urandom.img
0       urandom.img.gz
5.9G    total
# md5sum urandom.img
bc5ed6284fd2d2161296363edaea5a6d  urandom.img

校验和匹配,源文件的大小在原位解压缩时从 6GB 减少到 0。

但是有很多事情可能会出错......最好根本不要这样做,或者如果你真的必须这样做,至少使用一个可以进行更健全的错误检查的程序。上面的循环根本不保证数据在删除之前已被读取和处理。如果ddgunzip由于任何原因返回错误,fallocate仍然会高兴地扔掉它......所以如果您必须使用这种方法,最好编写一个更理智的read-and-eat程序。

答案2

如果您有第二个硬盘,您可以将压缩存档移到那里,然后解压缩并将其解档到您想要的位置:

$ mv archive.gz /mnt/somedrive/
$ cd /where/it/should/go
$ tar xvzf /mnt/somedrive/archive.gz

答案3

这取决于您想用它做什么。

如果是.tar.gz文件,不用先用.tar.gz解压就可以看到tar内容tar --list -zf /path/to/file

然后,如果您只想要 tgz 中的某些文件,则可以使用tar -xzvf /path/to/file relative/path/to/files/inside/tar.与往常一样,您可以使用 更改目标目录-C

这很糟糕,因为即使 .tar.gz 实际上是用 gz 压缩的 .tar 文件,这种情况也很常见,以至于 tar 可以选择内置地使用它,并传递标志-z。该标志仅适用于 gzip (也许 bzip2 也适用,我不确定),不适用于 xz 或 lz4。

作为一个额外的答案,如果 .gz 内的文件不是 tar,您始终可以将输出通过管道传输到分页器(如 less),这会将其放入内存中:gzcat /path/to/file | less

相关内容