Sıkıştırılmış büyük düz metin dosyası kısmen nasıl ayıklanır?


19

1.5 GB boyutunda bir zip dosyam var.

İçeriği saçma bir büyük düz metin dosyasıdır (60 GB) ve şu anda diskimde hepsini çıkarmak için yeterli alanım yok ya da sahip olsam bile, hepsini çıkarmak istemiyorum.

Kullanım durumuma gelince, içeriğin bazı bölümlerini inceleyip inceleyemeyeceğim.

Bu nedenle dosyayı bir akış olarak çıkartmak ve bir dosya aralığına erişmek istiyorum (normal bir metin dosyasında baş ve kuyruk aracılığıyla yapabilirsiniz).

Ya bellekle (örneğin 32 GB işaretinden başlayarak maks. 100 kb özü) veya satırlarla (bana düz metin satırlarını 3700-3900 verin).

Bunu başarmanın bir yolu var mı?


1
Ne yazık ki bir zip içinde tek bir dosya aramak mümkün değildir. Bu yüzden herhangi bir
yalnızlık

5
@plugwash Soruyu anladığım için amaç zip dosyasını (veya sıkıştırılmış dosyayı bile) okumaktan kaçınmak değil, sadece sıkıştırılmış dosyanın tamamını bellekte veya diskte saklamaktan kaçınmaktır . Temel olarak, açılmış dosyayı bir akış olarak ele alın .
ShreevatsaR

Yanıtlar:


28

Dosyaları gzipayıklayabileceğini unutmayın zip(en azından zipdosyadaki ilk giriş ). Bu arşivde yalnızca bir büyük dosya varsa şunları yapabilirsiniz:

gunzip < file.zip | tail -n +3000 | head -n 20

Örneğin 3000. satırdan başlayarak 20 satırı ayıklamak.

Veya:

gunzip < file.zip | tail -c +3000 | head -c 20

Baytlarla aynı şey için ( headdestekleyen bir uygulama varsayarak -c).

Arşivdeki rastgele üyeler için Unixy yöntemiyle:

bsdtar xOf file.zip file-to-extract | tail... | head...

İle headarasında yerleşiğini ksh93(zaman gibi /opt/ast/binönde olduğu $PATH), ayrıca yapabilirsiniz:

.... | head     -s 2999      -c 20
.... | head --skip=2999 --bytes=20

Her durumda gzip/ bsdtar/ unzipdosyasının her zaman dosyanın ayıklamak istediğiniz bölüme götüren tüm bölümünü açması (ve burada atması) gerektiğini unutmayın. Sıkıştırma algoritması bu şekilde çalışır.


Eğer gzip, bir gün diğer "z farkında" programları (halledebilirim zcat, zlessvs.) da işi?
ivanivan

@ivanivan, bunlar temel alırlar sistemlerde gzip(genellikle gerçek zless, ille de bir zcathangi bazı sistemlerde okumak için hala .Zevet sadece dosyaları).
Stéphane Chazelas

14

Unzip -p ve dd kullanan bir çözüm, örneğin 1000 blok ofset ile 10kb çıkarmak için:

$ unzip -p my.zip | dd ibs=1024 count=10 skip=1000 > /tmp/out

Not: Bunu gerçekten çok büyük verilerle denemedim ...


Genel olarak, tek bir arşiv içindeki birden fazla dosya unzip -l ARCHIVE, arşiv içeriğini listelemek ve unzip -p ARCHIVE PATHtek bir nesnenin içeriğini PATHstdout'a çıkarmak için kullanılabilir .
David Foerster

3
Genellikle, ddsayımı veya atlaması olan borularda kullanılması güvenilir değildir, çünkü 1024 bayta kadar olan birçok read()s'yi yapar . Bu nedenle, yalnızca boyutu unzip
1024'ün

4

Bu büyük zip dosyasının oluşturulması üzerinde kontrolünüz varsa, neden gzipve birleşimlerini kullanmayı düşünmüyorsunuz zless?

Bu, zlessçağrı cihazı olarak kullanmanıza ve dosyanın içeriğini ayıklama işlemine gerek kalmadan görüntülemenize olanak tanır .

Sıkıştırma biçimini değiştiremezseniz, bu kesinlikle işe yaramaz. Eğer öyleyse, zlessoldukça uygun gibi hissediyorum .


1
Yapmıyorum. Harici bir şirket tarafından sağlanan sıkıştırılmış dosyayı indiriyorum.
k0pernikus

3

Dosyanın belirli satırlarını görüntülemek için, çıktıyı Unix akış düzenleyicisine yönlendirin, sed . Bu, keyfi olarak büyük veri akışlarını işleyebilir, böylece verileri değiştirmek için bile kullanabilirsiniz. 3700-3900 satırlarını istediğiniz gibi görüntülemek için aşağıdakileri çalıştırın.

unzip -p file.zip | sed -n 3700,3900p

7
sed -n 3700,3900pdosyanın sonuna kadar okumaya devam eder. Bundan sed '3700,$!d;3900q'kaçınmak veya daha verimli kullanmak daha iyidir :tail -n +3700 | head -n 201
Stéphane Chazelas

3

Dosyanın başlangıcından sonuna kadar açmadan daha verimli bir şey yapmanın mümkün olup olmadığını merak ettim. Cevabın hayır olduğu anlaşılıyor. Ancak, bazı CPU'larda (Skylake) zcat | tailCPU'yu tam saat hızına yükseltmez. Aşağıya bakınız. Özel bir dekoder bu sorunu önleyebilir ve boru yazma sistemi çağrılarını kaydedebilir ve belki ~% 10 daha hızlı olabilir. (Veya güç yönetimi ayarlarını değiştirmezseniz Skylake'te ~% 60 daha hızlı).


skipbytesFonksiyonu olan özelleştirilmiş bir zlib ile yapabileceğiniz en iyi şey, sıkıştırılmış bloğu gerçekten yeniden yapılandırma işi yapmadan sonuna ulaşmak için bir sıkıştırma bloğundaki sembolleri ayrıştırmak olacaktır. Bu, aynı arabelleğin üzerine yazmak ve dosyada ilerlemek için zlib'in normal kod çözme işlevini çağırmaktan önemli ölçüde daha hızlı olabilir (muhtemelen en az 2x). Ama kimsenin böyle bir işlev yazıp yazmadığını bilmiyorum. (Ve dosya çözücünün belirli bir blokta yeniden başlamasına izin vermek için özel olarak yazılmadığı sürece bunun aslında işe yaramadığını düşünüyorum).

Blokları çözmeden Deflate bloklarını atlamanın bir yolu olduğunu umuyordum, çünkü bu çok daha hızlı olurdu . Huffman ağacı her bloğun başında gönderilir, böylece herhangi bir bloğun başından kodunu çözebilirsiniz (sanırım). Oh, bence dekoder durumu Huffman ağacından daha fazla, aynı zamanda kod çözülmüş verilerin önceki 32kiB'si ve bu varsayılan olarak blok sınırları boyunca sıfırlanmıyor / unutulmuyor. Aynı baytlara tekrar tekrar başvurulmaya devam edilebilir, bu nedenle dev sıkıştırılmış bir dosyada yalnızca bir kez görünebilir. (örneğin, bir günlük dosyasında, ana makine adı muhtemelen sıkıştırma sözlüğünde sürekli olarak "sıcak" kalır ve her örneği birincisine değil, öncekine başvurur).

zlibManuel kullanımdan gerektiği yazıyor Z_FULL_FLUSHçağrılırken deflatesen sıkıştırılmış akışı bu noktaya seekable olmasını istiyorsanız. "Sıkıştırma durumunu sıfırlar", bu yüzden bence, geriye dönük referanslar önceki blok (lar) içine gidebilirsiniz. Zip dosyanız zaman zaman tam floş blokları ile yazılmadığı sürece (her 1G veya bir şey sıkıştırma üzerinde ihmal edilebilir bir etki yaratacaktır), bence kod çözme işini başlangıçta benden daha fazla yapmak zorunda kalabilirsiniz. düşünce. Sanırım muhtemelen herhangi bir bloğun başında başlayamazsınız.


Bunun geri kalanı, istediğiniz ilk baytı içeren bloğun başlangıcını bulmak ve oradan kod çözmenin mümkün olacağını düşünürken yazılmıştır.

Ancak ne yazık ki, Deflate bloğunun başlangıcı sıkıştırılmış bloklar için ne kadar sürdüğünü göstermez . Sıkıştırılamaz veriler, öndeki bayt cinsinden 16 bit büyüklüğüne sahip sıkıştırılmamış bir blok türüyle kodlanabilir, ancak sıkıştırılmış bloklar şunları yapmaz: RFC 1951 formatı oldukça okunaklı bir şekilde açıklar . Dinamik Huffman kodlu bloklar bloğun önünde ağaca sahiptir (bu nedenle dekompresör akışta aramak zorunda değildir), bu nedenle kompresörün yazmadan önce tüm (sıkıştırılmış) bloğu hafızada tutması gerekir.

Maksimum geriye doğru referans mesafesi sadece 32kiB'dir, bu nedenle kompresörün sıkıştırılmamış çok fazla veriyi bellekte tutması gerekmez, ancak bu blok boyutunu sınırlamaz. Bloklar birden fazla megabayt uzunluğunda olabilir. (Disk, manyetik diskte bile buna değecek kadar büyüktür, ancak mevcut bloğun sonunu bulmadan bulmak mümkün olsaydı, sırayla belleğe okumak ve sadece RAM'de veri atlamak gibi).

zlib olabildiğince uzun bloklar yapar: Marc Adler'e göre , zlib sadece sembol arabelleği dolduğunda yeni bir blok başlatır ve varsayılan ayar 16.383 semboldür (değişmez değerler veya eşleşmeler)


Ben seq(son derece gereksiz ve muhtemelen büyük bir test değil) pv < /tmp/seq1G.gz | gzip -d | tail -c $((1024*1024*1000)) | wc -cçıktı gzipped, ancak bu sadece DDR4-2666 RAM ile 3.9GHz bir Skylake i7-6700k ~ 62 MiB / s sıkıştırılmış veri çalışır. Bu memcpy, önbelleğe sığmayacak kadar büyük blok boyutları için ~ 12 GiB / s hızına kıyasla yığın değişikliği olan 246MiB / s'lik sıkıştırılmış verilerdir .

( Skylake'in dahili CPU valisi yerine energy_performance_preferencevarsayılan olarak ayarlandığında , sadece 2,7GHz, ~ 43 MiB / s sıkıştırılmış veri ile çalışmaya karar verir. Ayarlamak için kullanırım . Muhtemelen bu tür sistem çağrıları gerçek CPU'ya bağlı görünmüyor güç yönetimi birimine çalışın.)balance_powerbalance_performancesudo sh -c 'for i in /sys/devices/system/cpu/cpufreq/policy[0-9]*/energy_performance_preference;do echo balance_performance > "$i";done'

TL: DR: Çok yavaş diskleriniz zcat | tail -colmadığı sürece hızlı bir CPU'ya bile CPU bağlıdır . gzip, üzerinde çalıştığı CPU'nun% 100'ünü kullandı (ve buna göre saat başına 1.81 talimatı çalıştırdı perf) ve tailçalıştırdığı CPU'nun 0.162'sini (0.58 IPC) kullandı. Sistem aksi halde çoğunlukla boştu.

Meltdown etrafında çalışmak için varsayılan olarak KPTI etkinleştirilmiş Linux 4.14.11-1-ARCH kullanıyorum , bu nedenle tüm bu writesistem çağrıları gzipeskisinden daha pahalı: /


Aramanın yerleşik olması unzipveya zcat(ancak normal zlibkod çözme işlevinin kullanılması) tüm bu boru yazmalarını kaydeder ve Skylake CPU'ların tam saat hızında çalışmasını sağlar. (Bazı yük türleri için bu hız aşırtma, CPU frekansı karar verme işlemini işletim sisteminden indiren Intel Skylake ve sonraki sürümlere özgüdür, çünkü CPU'nun ne yaptığı hakkında daha fazla veriye sahiptirler ve daha hızlı yukarı / aşağı rampa yapabilirler. normalde iyi, ancak burada Skylake daha muhafazakar bir vali ayarı ile tam hıza ulaşmıyor).

Hiçbir sistem çağrısı yok, sadece istediğiniz başlangıç ​​bayt konumuna ulaşana kadar L2 önbelleğine uyan bir arabelleği yeniden yazmak, muhtemelen en azından% birkaç fark yaratacaktır. Belki% 10 bile, ama burada sadece sayılar yapıyorum. zlibÖnbellek kapladığı alanın ne kadar büyük olduğunu ve her sistem çağrısındaki TLB floşunun (ve dolayısıyla uop-önbellek floşunun) KPTI etkinken ne kadar acı verdiğini görmek için herhangi bir ayrıntıda profilli değilim.


Gzip dosya biçimine arama dizini ekleyen birkaç yazılım projesi vardır . Kimsenin sizin için aranabilir sıkıştırılmış dosyalar oluşturmasını sağlayamazsanız bu size yardımcı olmaz, ancak gelecekteki diğer okuyucular fayda sağlayabilir.

Tahminen ne bu projelerin bir indeks zaman onlar sadece işin için tasarlanmış çünkü, bir dizin olmadan Deflate akımına atlamasına bilen bir kod çözme fonksiyonu var olan mevcut.


1

Zip dosyasını bir python oturumunda zf = zipfile.ZipFile(filename, 'r', allowZip64=True)açabilir ve açtıktan sonra, okumak için, zip arşivi ve okuma satırları vb. İçindeki herhangi bir dosyayı normal bir dosya gibi açabilirsiniz.

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.