Gzip sıkıştırması neden yinelenen veri bölümlerini ortadan kaldırmıyor?


30

Az önce sıkıştırılmış olup olmadığımı görmek için kopya dosyaları olan bir tar arşivi oluşturduğum küçük bir deney yaptım. Detaylar takip edilir (okuma zevkine yönelik sonuçlar):

$ dd if=/dev/urandom bs=1M count=1 of=a
  1+0 records in
  1+0 records out
  1048576 bytes (1.0 MB) copied, 0.114354 s, 9.2 MB/s
$ cp a b
$ ln a c
$ ll
  total 3072
  -rw-r--r-- 2 guido guido 1048576 Sep 24 15:51 a
  -rw-r--r-- 1 guido guido 1048576 Sep 24 15:51 b
  -rw-r--r-- 2 guido guido 1048576 Sep 24 15:51 c
$ tar -c * -f test.tar
$ ls -l test.tar 
  -rw-r--r-- 1 guido guido 2109440 Sep 24 15:51 test.tar
$ gzip test.tar 
$ ls -l test.tar.gz 
  -rw-r--r-- 1 guido guido 2097921 Sep 24 15:51 test.tar.gz
$ 

İlk önce rastgele verilerin 1MiB dosyasını oluşturdum (a). Sonra onu bir dosya b'ye kopyaladım ve c'ye de bağladım. Tarball oluştururken, tar görünüşte hardlink'in farkındaydı, çünkü tarball sadece ~ 2MiB idi ve ~ 3Mib değildi.

Şimdi, gzip'in a ve b kopyaları olduğu için tarball boyutunu ~ 1MiB'ye düşürmesini bekliyordum ve tarball içinde tekrarlanan 1MiB sürekli veri olması gerekiyordu, ancak bu gerçekleşmedi.

Bu neden? Ve bu durumlarda tarball'ı nasıl etkili bir şekilde sıkıştırabilirim?

Yanıtlar:


24

Gzip gzip, LZ77 ve Huffman kodlamasının bir kombinasyonu olan DEFLATE algoritmasına dayanır. Giriş akışını anında oluşturulmuş bir sözlük kullanarak sıkıştırılmış sembollere dönüştürerek ve kopyaları izleyerek çalışan kayıpsız bir veri sıkıştırma algoritmasıdır. Ancak 32K'dan fazla ayrılmış kopyaları bulamıyor. 1 MB'lik kopyaları birbirinden ayırmasını beklemek gerçekçi değil.


Yeterince adil! Akarsu üzerinde çalışmayan herhangi bir alternatif biliyor musunuz?
Guido

1
Sorununla ilgili paket bir çözüm bilmiyorum. Bunun tekrar eden, ciddi bir sorun olacağını umuyorsam, ben (şahsen) n-way cmp (compare) işlemlerini kopyaları bulmak için yapan bir betikle saldıracağım, listeyi bir dosyaya yazacağım, sonra sadece tar + gzip benzersiz öğeler + liste. Geri yüklemek için, ungzip ve untar komutunu vermek için ikinci bir komut dosyası kullanırdım, sonra listeden dupleri oluşturur. Diğer bir alternatif ise, tar'ları tespit ettiğini bildiğiniz için dupleri sert linklere çevirmek olacaktır. Üzgünüm, muhtemelen umduğun şeyin bu olmadığını biliyorum.
Nicole Hamilton

1
gzip ve bzip2'nin her ikisinin de tasarımları nedeniyle nispeten "akış dostu" olması gerekir - bir borunun parçası olarak çalışabilmek kesinlikle gereklidir. Burada aradığınız şey aslında sadece tekilleştirme ve sadece sıkıştırma değil. Katran işlemi iki parçaya böldüğü için - sadece katran ile arşivleme ve ardından sıkıştırmak için filtre olarak ikinci bir program kullanma. Aramalarımda veri tekilleştirme ile sıkıştırılmış bir arşiv bulamadım, ancak önceki ilgili soruyu buldum. superuser.com/questions/286414/…
Stephanie,

2
@Stephanie, NicoleHamilton: Orada en.wikipedia.org/wiki/Lrzip#Lrzip .
Mekanik salyangoz 0 '

1
@Guido Elbette hiçbir şey, bir akışta hatırlamadığı bir şeyin kopyalarını kaldıramaz, ama onun gibi bir şeyi xz -9 -M 95%bile deneyemez xz -M 95% --lzma2=preset=9,dict=1610612736. Hızlı olmayacak, ancak kopyalarınızın sonuçta bırakılması muhtemel değil.
Eroen

39

Nicole Hamilton doğru notlargzip nedeniyle küçük sözlük boyutuna uzak tekrarlanan verileri bulamazlar.

bzip2 benzer, çünkü 900 KB bellek ile sınırlıdır.

Bunun yerine, deneyin:

LZMA / LZMA2 algoritması ( xz, 7z)

LZMA algoritması Deflate ile aynı ailededir, ancak çok daha büyük bir sözlük boyutu kullanır (özelleştirilebilir; varsayılan 384 MB gibi bir şeydir). xzEn son Linux dağıtımları üzerinde varsayılan olarak yüklü olmalıdır yarar, benzer gzipve LZMA kullanır.

LZMA daha uzun menzilli fazlalık tespit ettiğinden, verilerinizi burada tekilleştirebilir. Ancak, Gzip'ten daha yavaştır.

Diğer bir seçenek ise 7z, p7zipvarsayılan olarak LZMA kullanan (LZMA yazarı tarafından yazılmış) bir arşivleyici (tek akışlı kompresör yerine) olan 7-zip'dir ( pakette). 7-zip arşivleyici, kendi formatını arşivlerken dosya düzeyinde (aynı uzantıdaki dosyalara bakarak) kendi veri tekilleştirmesini çalıştırır .7z. Değiştirmeye çekinmiyorsanız Bu araç olduğu tarile 7z, sen tekilleştirilmez aynı dosyaları olsun. Bununla birlikte, 7z nanosaniye zaman damgalarını, izinleri veya xattr'leri korumaz, bu nedenle ihtiyaçlarınızı karşılamayabilir.

lrzip

lrzipGzip / Deflate, bzip2, lzop veya LZMA gibi geleneksel bir algoritmaya vermeden önce uzun mesafeli artıklığı gidermek için verileri önceden işleyen bir kompresördür. Burada verdiğiniz örnek veriler için gerekli değildir; Giriş verilerinin belleğe sığabilecek olandan daha büyük olması durumunda kullanışlıdır.

Bu tür veriler için (kopyalanamayan sıkıştırılamaz parçalar), lzopsıkıştırmayı (çok hızlı) kullanmanız gerekir lrzip, çünkü veri tekilleştirildikten sonra tamamen rastgele verileri sıkıştırmak için daha fazla çaba göstermenin bir faydası yoktur.

Bup ve Obnam

Soru etiketlediğinizden, buradaki amacınız verileri yedeklemekse, Bup veya Obnam gibi bir veri tekilleştirme programı kullanmayı düşünün .


Bu IRZIP ilginç görünüyor. Geleneksel olmayan çözümler için bilinen bir yazarı bile var. Şimdi yedekleme komut dosyalarımı düzeltmem gerekecek. Tekrar.
Eroen

3
+1 Vay, orada ne kadar bilgi / deneyim çeşmesi var. Takdir. Veri tekilleştirme özellikli dosya sistemlerini karışıma ekleyebilir miyim? ZFS (ve sanırım Btrfs'nin buna uygun olduğu düşünülüyor) - blok hizalı çoğaltmayla çalışacak
se

LZMA2 sıkıştırma ve bir 1536Mb dik ölçüsü (Windows GUI'de mevcut maksimum boyut) kullanarak 7Zip benim için harika!
Leopoldo Sanczyk

2

Yedekleme durumunda, muhtemelen büyük miktarda küçük dosya kümesiyle, sizin için işe yarayabilecek bir püf noktası, tar içindeki dosyaları uzantısına göre sıralamaktır:

find archive_dir -type f | rev | sort | rev | tar czf my_archive.tar.gz -I -

Tüm bunları kestirdim rev(neden tersine çevirip sonra sıralayalım?) Ve "-r, --reverse"sort seçeneğine baktım (gerçekte neden ters çevirmek istediğinizi bile bilmiyorum). Ama senin düşünüyorum tarseçenek " -I" Sen öyle düşündüğün yapmaz " -I, --use-compress-program PROG" , muhtemelen istiyorum "-T, --files-den FILE"
Xen2050

| tar czf my_archive.tar.gz -I -Olması gerektiğine inanıyorum| xargs tar Azf my_archive.tar.gz
Olivier Dulac

@ Xen2050, akıştaki revsatır sırasını değil, her satırdaki karakter sırasını tersine çevirir. Bu nedenle sort, dosyaları uzantılarına göre gruplandırır. Stdin'deki dosya listesini sağlayan -I -olması gerektiğinden şüpheleniyorum -T -.
billyjmc

@billyjmc Görüyorum ki, bu revzaten Linux'ta pek çok eklenti olmadığı için, uzatma işlemiyle sonuçlanacaktı .
Boyuta

2

gzipÇiftleri bulamaz, xzbüyük sözlük boyutunda bile olmaz. Yapabilecekleriniz kullanmaktır mksquashfs- bu aslında kopya alanını koruyacaktır.

İkisi aynı olan üç rastgele ikili dosya (64MB) ile xzve bazı hızlı test sonuçları mksquashfs:

Kurmak:

mkdir test
cd test
dd if=/dev/urandom of=test1.bin count=64k bs=1k
dd if=/dev/urandom of=test2.bin count=64k bs=1k
cp test{2,3}.bin
cd ..

Squashfs:

mksquashfs test/ test.squash
> test.squash - 129M

xz:

XZ_OPT='-v --memlimit-compress=6G --memlimit-decompress=512M --lzma2=preset=9e,dict=512M --extreme -T4 ' tar -cJvf test.tar.xz test/
> test.tar.xz - 193M

Mksquashfs sadece dosya düzeyinde kopyalar mı bulur, yoksa daha küçük parçalarda da çalışır mı? Yani: Aynı zamanda biraz farklı fakat çoğunlukla aynı dosyaları sıkıştırır mı?
Chaos_99

Bu sadece dosya bazında çalışır. Bu üç test dosyasını sıkıştırılmamış tar arşivine tararken ve bunları mksquashfs ile sıkıştırırken görebilirsiniz. Öte yandan, mksqashfs, stdout'taki kopyaları bulurken rapor verecektir Number of duplicate files found.
Izzy

1

Benim sistem üzerinde lzma test.tarbir 106'3175 bayt (1.1M) test.tar.lzma dosyasında sonuçları


1

Mekanik salyangozun cevabına ek olarak:

Sıkıştırılmamış tek dosyanın dosya boyutu (veya daha doğrusu kopyalar arasındaki mesafe) sözlük boyutunu aşıyorsa, xz (veya lzma) bile kopyaları bulamaz. xz (veya lzma) en yüksek ayarda bile -9esadece bunun için 64 MB ayırıyor .

Neyse ki seçeneği ile kendi diktoner bedeninizi belirleyebilirsiniz --lzma2=dict=256MB (sadece --lzma1=dict=256MBlzma diğer adını komuta kullanırken izin verilir)

Ne yazık ki, yukarıdaki örnekte olduğu gibi özel sıkıştırma zincirleriyle ayarları geçersiz kıldığınızda, diğer tüm parametrelerin varsayılan değerleri -9e ile aynı seviyeye ayarlanmaz. Bu nedenle, sıkıştırma yoğunluğu tek dosyalar için yüksek değildir.


-2

komut satırı anahtarı olmayan gzip, sıkıştırma için olası en düşük algoritmayı kullanır.

Kullanmayı deneyin:

gzip -9 test.tar

Daha iyi sonuçlar almalısın


1
Pek sayılmaz, fark az. Ben de bzip2'yi benzer sonuçlarla denedim.
Guido

komut satırı anahtarı olmayan gzip, sıkıştırma için olası en düşük algoritmayı kullanır. => Bu doğru değil - "man gzip", "(t) varsayılan sıkıştırma düzeyinin -6 (yani, hız pahasına yüksek sıkıştırma yönünde önyargılı)" olduğunu belirtir. Derlenmiş varsayılan ayarlar GZIP ortam değişkeni tarafından geçersiz kılınmazsa, bildiğim tüm gzip sürümleri için geçerlidir. Verilen "-9" seviyesi bile burada verilen cevaplarda açıklandığı gibi size yardımcı olmaz.
Gunter Ohrner
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.