就地解压 gzip 文件

Nox*_*bru 7 gzip

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

有没有办法在“删除时”解压缩它?

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

提前致谢!

fro*_*utz 8

有没有办法在“删除时”解压缩它?

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

如果 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
Run Code Online (Sandbox Code Playgroud)

urandom.img.gz文件占用了76%的可用空间,所以不能直接解压。管道未压缩的结果,md5sum以便我们稍后验证:

# gunzip < urandom.img.gz | md5sum
bc5ed6284fd2d2161296363edaea5a6d  -
Run Code Online (Sandbox Code Playgroud)

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

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
Run Code Online (Sandbox Code Playgroud)

结果:

# 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
Run Code Online (Sandbox Code Playgroud)

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

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