Najszybszy sposób opracowania nieskompresowanego rozmiaru dużego pliku GZIPPED


24

Po skompresowaniu pliku istnieje sposób szybkiego zapytania go o rozmiar nieskompresowanego pliku (bez jego dekompresji), szczególnie w przypadkach, gdy rozmiar nieskompresowanego pliku jest większy niż 4 GB.

Zgodnie z RFC https://tools.ietf.org/html/rfc1952#page-5 możesz zapytać o ostatnie 4 bajty pliku, ale jeśli nieskompresowany plik miał> 4 GB, wówczas wartość reprezentuje tylkouncompressed value modulo 2^32

Tę wartość można również odzyskać, uruchamiając gunzip -l foo.gz, jednak kolumna „nieskompresowana” po prostu zawiera uncompressed value modulo 2^32ponownie, prawdopodobnie podczas odczytu stopki, jak opisano powyżej.

Zastanawiałem się tylko, czy istnieje sposób na uzyskanie rozmiaru nieskompresowanego pliku bez konieczności jego pierwszej dekompresji, byłoby to szczególnie przydatne w przypadku, gdy pliki spakowane gzip zawierają ponad 50 GB danych i rozpakowanie ich przy użyciu metod takich jak gzcat foo.gz | wc -c


EDYCJA: Ograniczenie 4 GB jest otwarcie potwierdzone na manstronie gzipnarzędzia dołączonego do OSX ( Apple gzip 242)

  BUGS
    According to RFC 1952, the recorded file size is stored in a 32-bit
    integer, therefore, it can not represent files larger than 4GB. This
    limitation also applies to -l option of gzip utility.

2
+1 dobre pytanie! Podejrzewam, że odpowiedź brzmi „nie”, że format nagłówka został zaprojektowany w czasie poprzedzającym takie rozmiary plików. Myślenie o tym gzipmusi być starsze niż wielu użytkowników w tej społeczności!
Celada,

2
gzipwyszedł w 1992 roku. Byłbym zaskoczony, gdyby w okolicy kręciło się wielu 23-latków. Jestem pewien, że są takie, ale z tego, co mogę powiedzieć, mediana wieku to około 30-35 lat.
Bratchley,

2
Może to być dobry moment na przejście na takie, xzktóre nie mają tego ograniczenia. GNU przechodzi na xz.
Stéphane Chazelas,

@ StéphaneChazelas Ciekawe. Niestety pliki, którymi się interesuję, są poza moją kontrolą (tzn. Otrzymujemy je skompresowane), ale z pewnością wygląda na to, xz że „rozwiązałoby” ten problem.
djhworld,

Odpowiedzi:


11

Uważam, że najszybszym sposobem jest modyfikacja gzip, aby testowanie w trybie pełnym wyświetlał liczbę zdekompresowanych bajtów; w moim systemie, z plikiem 7761108684-bajt, dostaję

% time gzip -tv test.gz
test.gz:     OK (7761108684 bytes)
gzip -tv test.gz  44.19s user 0.79s system 100% cpu 44.919 total

% time zcat test.gz| wc -c
7761108684
zcat test.gz  45.51s user 1.54s system 100% cpu 46.987 total
wc -c  0.09s user 1.46s system 3% cpu 46.987 total

Aby zmodyfikować gzip (1.6, dostępny w Debianie), łatka wygląda następująco:

--- a/gzip.c
+++ b/gzip.c
@@ -61,6 +61,7 @@
 #include <stdbool.h>
 #include <sys/stat.h>
 #include <errno.h>
+#include <inttypes.h>

 #include "closein.h"
 #include "tailor.h"
@@ -694,7 +695,7 @@

     if (verbose) {
         if (test) {
-            fprintf(stderr, " OK\n");
+            fprintf(stderr, " OK (%jd bytes)\n", (intmax_t) bytes_out);

         } else if (!decompress) {
             display_ratio(bytes_in-(bytes_out-header_bytes), bytes_in, stderr);
@@ -901,7 +902,7 @@
     /* Display statistics */
     if(verbose) {
         if (test) {
-            fprintf(stderr, " OK");
+            fprintf(stderr, " OK (%jd bytes)", (intmax_t) bytes_out);
         } else if (decompress) {
             display_ratio(bytes_out-(bytes_in-header_bytes), bytes_out,stderr);
         } else {

Czy nadal buduje rzeczywiste dane wewnętrznie, czy jest -tjuż zoptymalizowany pod tym względem? Ulepszenie jest wystarczająco małe, aby wyglądało na to, że zaoszczędziłeś tylko czas wyjściowy.
frostschutz

Tak, musi zdekompresować wszystko, aby ustalić oryginalny rozmiar ... To oszczędza tylko czas wyjściowy, ale myślę, że to wszystko, co można zapisać.
Stephen Kitt

Ciekawe, tak, myślałem, że trzeba zmienić kod, aby faktycznie to zadziałało. Niestety w moim przypadku pliki, które mnie interesują, tak naprawdę nie są pod moją kontrolą, otrzymuję je od zewnętrznego podmiotu, więc nie będę w stanie ich skompresować. Myślę, że jedynym sposobem na pełną obsługę plików> 4 GB byłoby załatanie gzip, aby miał 12-bajtową stopkę, 4 bajty dla CRC i 8 bajtów (64-bit) dla rozmiaru pliku. Jednak to zepsuje kompatybilność wsteczną z istniejącymi gzips!
djhworld

Rozwiązanie, które podałem powyżej, nie obejmuje początkowej kompresji plików, nawet jeśli działam gzip; Po prostu uruchamiam gzipskompresowane pliki, które nie kompresują ich, tylko je weryfikują. (Łata jest szybkim i brudnym sprawdzianem koncepcji, wymaga kilku dodatkowych zmian do pracy gunzip.)
Stephen Kitt

@StephenKitt Ah ciekawe! Jeszcze lepszym / bardziej brudnym włamaniem byłoby osadzenie tych danych w FCOMMENTterenie. W ten sposób użytkownicy mogą zapytać o zakres bajtów, aby pobrać te dane. Byłoby to przydatne w moim przypadku, szczególnie w przypadku przedmiotów przechowywanych w Amazon S3
djhworld

0

Jeśli potrzebujesz wielkość skompresowanego pliku lub zestawu plików, najlepiej jest do stosowania tar -zlub tar -jzamiast gzipjako tarobejmuje nieskompresowany format plików. Użyj, lesspipeaby zerknąć na listę plików:

aptitude install lesspipe
lesspipe <compressed file> | less

Jeśli lessjest skonfigurowany do użycia lesspipe:

less <compressed file>

Pamiętaj jednak, że może to potrwać bardzo długo. Jednak twój system pozostaje responsywny, co pozwala zabić proces dekompresji.

Innym podejściem byłoby zalogowanie skompresowanego współczynnika i zapytanie tego pliku [tekstowego] zamiast:

gzip --verbose file 2>&1 | tee file.gz.log
file:    64.5% -- replaced with file.gz

Wymaga jednak obliczeń, aby znaleźć rzeczywisty rozmiar pliku.

Możesz również zrobić to samo z tar, co w rzeczywistości robię z kopiami zapasowymi o dużych rozmiarach, ponieważ zapobiega to przejściu przez cały proces dekompresji, aby uzyskać na przykład tylko rozmiar lub nazwę pliku.


2
Czy tar.gz nie musi być również całkowicie zdekompresowany, aby uzyskać listę wszystkich plików?
frostschutz

Rzeczywiście tak musi być. To jedyny sposób na uzyskanie nieskompresowanego rozmiaru pliku. Z tarmasz oryginalny rozmiar pliku zalogowany w archiwum. Z zipdrugiej strony nie jestem pewien, czy zachowuje się inaczej.

1
W tym momencie OP może równie dobrze wykonać wc -cpolecenie.
Bratchley,

@Bratchley oczywiście. Ale uzyskanie wszystkich wyników zajęłoby sporo czasu. Stąd moje dwie sugestie dotyczące rejestrowania rozmiarów plików.

0

Co powiesz na

gzip -l file.gz|tail -n1|awk '{print $2}'

numfmt --to=iec $(gzip -l file.gz|tail -n1|awk '{print $2}')

1
To nie działa w przypadku dużych plików, jak wyjaśniono w OP.
Stephen Kitt

-2
gunzip -c $file | wc -c

To zajmie dużo czasu, ale da ci ostateczny rozmiar w bajtach.


5
Właśnie tego PO stara się unikać.
depquid
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.