Saya punya file zip dengan ukuran 1,5 GB.
Isinya adalah satu file teks biasa besar yang konyol (60 GB) dan saat ini saya tidak memiliki cukup ruang pada disk saya untuk mengekstraksi semuanya juga tidak ingin mengekstrak semuanya, bahkan jika saya punya.
Sedangkan untuk kasus penggunaan saya, akan cukup jika saya dapat memeriksa bagian dari konten.
Karenanya saya ingin membuka zip file sebagai aliran dan mengakses berbagai file (seperti dapat melalui kepala dan ekor pada file teks normal).
Baik dengan memori (mis. Ekstrak maks 100kb mulai dari tanda 32GB) atau dengan garis (beri saya garis teks biasa 3700-3900).
Apakah ada cara untuk mencapainya?
text-processing
zip
k0pernikus
sumber
sumber
Jawaban:
Catatan yang
gzip
dapat mengekstrakzip
file (setidaknya entri pertama dalamzip
file). Jadi jika hanya ada satu file besar di arsip itu, Anda dapat melakukannya:Untuk mengekstrak 20 baris dimulai dengan 3000 baris misalnya.
Atau:
Untuk hal yang sama dengan byte (dengan asumsi
head
implementasi yang mendukung-c
).Untuk setiap anggota yang sewenang-wenang dalam arsip, dengan cara Unixy:
Dengan
head
bawaanksh93
(seperti saat/opt/ast/bin
ada di depan$PATH
), Anda juga dapat melakukan:Perhatikan bahwa dalam setiap kasus
gzip
/bsdtar
/unzip
akan selalu perlu membuka kompresi (dan membuang di sini) seluruh bagian file yang mengarah ke bagian yang ingin Anda ekstrak. Begitulah cara kerja algoritma kompresi.sumber
gzip
bisa mengatasinya, akan yang lain "z sadar" utilitas (zcat
,zless
, dll) juga bekerja?gzip
(umumnya benarzless
, tidak haruszcat
yang pada beberapa sistem masih membaca.Z
file saja), ya.Satu solusi menggunakan unzip -p dan dd, misalnya untuk mengekstrak 10kb dengan 1000 blok offset:
Catatan: Saya tidak mencoba ini dengan data yang sangat besar ...
sumber
unzip -l ARCHIVE
untuk mendaftar konten arsip danunzip -p ARCHIVE PATH
untuk mengekstraksi konten objek tunggalPATH
ke stdout.dd
pada pipa dengan hitungan atau melewatkan tidak dapat diandalkan karena akan melakukan itu banyakread()
s dari hingga 1024 byte. Jadi itu hanya dijamin untuk bekerja dengan baik jikaunzip
menulis ke pipa dalam potongan yang ukurannya adalah kelipatan 1024.Jika Anda memiliki kendali atas pembuatan file zip besar itu, mengapa tidak mempertimbangkan menggunakan kombinasi dari
gzip
danzless
?Ini akan memungkinkan Anda untuk menggunakan
zless
sebagai pager dan melihat isi file tanpa harus repot dengan ekstraksi.Jika Anda tidak dapat mengubah format kompresi maka ini jelas tidak akan berhasil. Jika demikian, saya merasa
zless
agak nyaman.sumber
Untuk melihat baris tertentu dari file, pipa output ke editor aliran Unix, sed . Ini dapat memproses aliran data besar secara sewenang-wenang, sehingga Anda bahkan dapat menggunakannya untuk mengubah data. Untuk melihat baris 3700-3900 saat Anda bertanya, jalankan yang berikut ini.
sumber
sed -n 3700,3900p
akan terus membaca hingga akhir file. Lebih baik digunakansed '3700,$!d;3900q'
untuk menghindari itu, atau bahkan secara umum lebih efisien:tail -n +3700 | head -n 201
Saya bertanya-tanya apakah mungkin untuk melakukan sesuatu yang lebih efisien daripada mendekompresi dari awal file sampai ke titik. Tampaknya jawabannya adalah tidak. Namun, pada beberapa CPU (Skylake)
zcat | tail
tidak meningkatkan CPU hingga kecepatan jam penuh. Lihat di bawah. Decoder kustom dapat menghindari masalah itu dan menghemat panggilan sistem penulisan pipa, dan mungkin ~ 10% lebih cepat. (Atau ~ 60% lebih cepat di Skylake jika Anda tidak mengubah pengaturan manajemen daya).Yang terbaik yang dapat Anda lakukan dengan zlib yang disesuaikan dengan a
skipbytes
fungsi adalah mengurai simbol dalam blok kompresi untuk sampai ke akhir tanpa melakukan pekerjaan merekonstruksi blok dekompresi. Ini bisa lebih cepat secara signifikan (mungkin setidaknya 2x) daripada memanggil fungsi decode reguler zlib untuk menimpa buffer yang sama dan bergerak maju dalam file. Tapi saya tidak tahu apakah ada yang menulis fungsi seperti itu. (Dan saya pikir ini tidak benar-benar berfungsi kecuali file itu ditulis khusus untuk memungkinkan decoder untuk memulai kembali pada blok tertentu).Saya berharap ada cara untuk melewati blok Deflate tanpa memecahkan kode mereka, karena itu akan jauh lebih cepat. Pohon Huffman dikirim pada awal setiap blok, sehingga Anda dapat memecahkan kode dari awal setiap blok (saya pikir). Oh, saya pikir negara decoder lebih dari pohon Huffman, itu juga 32kiB data yang diterjemahkan sebelumnya, dan ini tidak diatur ulang / dilupakan melintasi batas blok secara default. Byte yang sama dapat terus dirujuk berulang kali, jadi mungkin hanya muncul sekali dalam satu file terkompresi raksasa. (mis. dalam file log, nama host mungkin tetap "panas" dalam kamus kompresi sepanjang waktu, dan setiap contoh merujuk pada yang sebelumnya, bukan yang pertama).
The
zlib
pengguna mengatakan Anda harus menggunakanZ_FULL_FLUSH
saat memanggildeflate
jika Anda ingin aliran dikompresi menjadi seekable ke titik itu. Ini "me-reset kondisi kompresi", jadi saya pikir tanpa itu, referensi mundur dapat masuk ke blok sebelumnya. Jadi kecuali file zip Anda ditulis dengan blok full-flush sesekali (seperti setiap 1G atau sesuatu akan memiliki dampak yang dapat diabaikan pada kompresi), saya pikir Anda harus melakukan lebih banyak pekerjaan pengodean ulang ke titik yang Anda inginkan daripada yang saya awalnya berpikir. Saya kira Anda mungkin tidak dapat memulai di awal blok apa pun.Sisa dari ini ditulis ketika saya berpikir mungkin untuk menemukan awal dari blok yang berisi byte pertama yang Anda inginkan, dan decode dari sana.
Namun sayangnya, awal blok Deflate tidak menunjukkan berapa lama , untuk blok terkompresi. Data yang tidak dapat dikompres dapat dikodekan dengan tipe blok terkompresi yang memiliki ukuran 16-bit dalam byte di depan, tetapi blok terkompresi tidak: RFC 1951 menggambarkan format yang cukup mudah dibaca . Blok dengan pengkodean Huffman dinamis memiliki pohon di bagian depan blok (sehingga decompressor tidak harus mencari dalam aliran), sehingga kompresor harus menyimpan seluruh (terkompresi) blok dalam memori sebelum menulisnya.
Jarak referensi mundur maksimum hanya 32kiB, sehingga kompresor tidak perlu menyimpan banyak data yang tidak terkompresi dalam memori, tetapi itu tidak membatasi ukuran blok. Panjang blok bisa beberapa megabyte. (Ini cukup besar untuk disk mencari nilai bahkan pada drive magnetik, vs. membaca sekuensial ke dalam memori dan hanya melewatkan data dalam RAM, jika mungkin untuk menemukan akhir dari blok saat ini tanpa menguraikannya).
zlib membuat blok selama mungkin: Menurut Marc Adler , zlib hanya memulai blok baru ketika buffer simbol terisi, yang dengan pengaturan default adalah 16.383 simbol (literal atau korek api)
Saya gzip output
seq
(yang sangat berlebihan dan dengan demikian mungkin bukan tes yang bagus), tetapipv < /tmp/seq1G.gz | gzip -d | tail -c $((1024*1024*1000)) | wc -c
hanya berjalan pada ~ 62 MiB / s data terkompresi pada Skylake i7-6700k di 3,9GHz, dengan DDR4-2666 RAM. Itu 246MiB / s dari data yang terkompresi, yang merupakan perubahan besar dibandingkan denganmemcpy
kecepatan ~ 12 GiB / s untuk ukuran blok yang terlalu besar untuk disimpan dalam cache.(Dengan
energy_performance_preference
set ke defaultbalance_power
sebagai gantinyabalance_performance
, gubernur CPU internal Skylake memutuskan untuk hanya berjalan pada 2.7GHz, ~ 43 MiB / s data terkompresi. Saya gunakansudo sh -c 'for i in /sys/devices/system/cpu/cpufreq/policy[0-9]*/energy_performance_preference;do echo balance_performance > "$i";done'
untuk mengubah itu. Mungkin panggilan sistem yang sering seperti itu tidak terlihat seperti terikat CPU nyata bekerja ke unit manajemen daya.)TL: DR:
zcat | tail -c
adalah CPU yang terikat bahkan pada CPU yang cepat, kecuali jika Anda memiliki disk yang sangat lambat. gzip menggunakan 100% CPU yang digunakannya (dan menjalankan 1,81 instruksi per jam, menurutperf
), dantail
menggunakan 0,162 CPU yang digunakannya (0,58 IPC). Sistem itu sebagian besar menganggur.Saya menggunakan Linux 4.14.11-1-ARCH, yang memiliki KPTI diaktifkan secara default untuk bekerja di sekitar Meltdown, jadi semua
write
panggilan sistem digzip
lebih mahal daripada sebelumnya: /Memiliki pencarian bawaan untuk
unzip
atauzcat
(tetapi masih menggunakanzlib
fungsi decode biasa ) akan menyimpan semua pipa tersebut, dan akan membuat CPU Skylake berjalan pada kecepatan jam penuh. (Ini downclocking untuk beberapa jenis beban adalah unik untuk Intel Skylake dan kemudian, yang memiliki beban pengambilan keputusan frekuensi CPU dari OS, karena mereka memiliki lebih banyak data tentang apa yang CPU lakukan, dan dapat meningkatkan / menurunkan lebih cepat. Ini adalah biasanya baik, tetapi di sini mengarah ke Skylake yang tidak mencapai kecepatan penuh dengan pengaturan gubernur yang lebih konservatif).Tidak ada panggilan sistem, hanya menulis ulang buffer yang sesuai dengan cache L2 sampai Anda mencapai posisi byte awal yang Anda inginkan, mungkin akan membuat perbedaan setidaknya beberapa%. Mungkin bahkan 10%, tapi saya hanya membuat angka di sini. Saya belum memprofilkan
zlib
detail untuk melihat seberapa besar jejak cache yang dimilikinya, dan seberapa banyak TLB flush (dan dengan demikian uop-cache flush) pada setiap panggilan sistem sakit dengan KPTI diaktifkan.Ada beberapa proyek perangkat lunak yang menambahkan indeks pencarian ke format file gzip . Ini tidak membantu Anda jika Anda tidak dapat membuat siapa pun menghasilkan file terkompresi yang dapat dicari untuk Anda, tetapi pembaca lain di masa mendatang mungkin mendapat manfaat.
Agaknya tak satu pun dari proyek-proyek ini memiliki fungsi decode yang tahu bagaimana untuk melewati melalui aliran Deflate tanpa indeks, karena mereka hanya dirancang untuk bekerja ketika indeks adalah tersedia.
sumber
Anda dapat membuka file zip dalam sesi python, menggunakan
zf = zipfile.ZipFile(filename, 'r', allowZip64=True)
dan setelah dibuka Anda dapat membuka, untuk membaca, file apa pun di dalam arsip zip dan membaca baris, dll., Dari itu seolah-olah itu adalah file normal.sumber