Gzip

就地解壓gzip文件

  • January 31, 2017

我有一個用 gzip 壓縮的大文件(420 GB),我想解壓縮它,但我的硬碟沒有空間來儲存整個壓縮文件及其內容。

有沒有辦法在“刪除它的同時”解壓它?

如果它有幫助, gzip -l 說裡面只有一個文件(這是一個 tar 文件,我也必須以某種方式分離)

提前致謝!

有沒有辦法在“刪除它的同時”解壓它?

這就是你所要求的。但這可能不是你真正想要的。使用風險自負。

如果 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程序。

引用自:https://unix.stackexchange.com/questions/341458