我有一个用 gzip 压缩的大文件(420 GB),我想解压缩它,但我的硬盘没有空间来存储整个压缩文件及其内容。
有没有一种方法可以“在删除它的同时”对其进行解压缩?
如果有帮助的话, gzip -l 说里面只有一个文件(这是一个 tar 文件,我也必须以某种方式将其分离)
提前致谢!
答案1
有没有一种方法可以“在删除它的同时”对其进行解压缩?
这就是你所要求的。但这可能不是您真正想要的。使用风险自负。
如果 420GB 文件存储在具有稀疏文件和打孔支持的文件系统上(例如ext4
,xfs
,但不是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。
但是有很多事情可能会出错......最好根本不要这样做,或者如果你真的必须这样做,至少使用一个可以进行更健全的错误检查的程序。上面的循环根本不保证数据在删除之前已被读取和处理。如果dd
或gunzip
由于任何原因返回错误,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