Pytanie Jak utworzyć nieskompresowane archiwum ZIP w Javie


Korzystam z pakietu narzędziowego Zip Java i chciałem wiedzieć, jak utworzyć plik ZIP bez kompresji. Ustawienie poziomu na 0 nie pomaga. Czy to jest poprawne?

Ponadto, kiedy użyłem STORED metoda, zgłasza następujący wyjątek:

java.util.zip.ZipException: STORED entry missing size, compressed size, or crc-32

Mogę ustawić rozmiar, ale teraz następujący wyjątek jest zgłaszany:

java.util.zip.ZipException: invalid entry crc-32 

Po prostu podążam za wszystkimi dostępnymi przykładami, szukając w Internecie i nie jestem w stanie tego właściwie zrozumieć. Byłoby wspaniale, gdyby ktoś mi w tym pomógł i dostarczył mi sugestii, by rozwiązać problem, który mógłbym robić.


18
2017-07-30 14:29


pochodzenie


Te stałe int są "akcentem kodu" z innego wieku (prawdopodobnie C) ... Chciałabym, żeby David Connelly przeczytał o Java wyliczeniach zanim napisał ZipOutputStream. - Christophe Roussy
@ CristristopheRoussy To by było raczej trudne, jak ZipOutputStream pojawił się wiele lat przed wyliczeniem. - user207421


Odpowiedzi:


Jestem nieufny aperkins rozwiązanie (skoro usunięte), ale wiem, dlaczego zadziałało. Linia (która od tego czasu została poprawiona w jego odpowiedzi)

zipOut.setLevel(ZipOutputStream.STORED); // accidentally right

używał wartości statycznej ZipOutputStream.STORED, co jest przypadkowe 0. Więc ta linia robi ustawienie poziom używany przez domyślną metodę DEFLATED do zerowej kompresji (jest to oczywiście to, co chcesz zrobić, ale zdarzyło się, że działa tylko przez szczęście). Aby uzyskać to, co chcesz, jawnie i bezpiecznie, użyj tego:

zipOut.setMethod(ZipOutputStream.DEFLATED); // this line optional
zipOut.setLevel(0);

lub

zipOut.setLevel(Deflater.NO_COMPRESSION);

Jeśli użyjesz

zipOut.setMethod(ZipOutputStream.STORED);
zipOut.setLevel(Deflater.NO_COMPRESSION);

prawdopodobnie otrzymasz wyjątek, który Keya zanotowała w oryginalnym pytaniu. wierzę Christian Schlichtherle jest w porządku; otrzymujesz wyjątki, ponieważ nie ustawiasz CRC we wpisie. Następstwem tego jest użycie metody STORED, najpierw trzeba przeczytać cały plik wejściowy lub znaleźć inny sposób ustawienia rozmiaru, skompresowanego rozmiaru (musi być równy) i CRC przed wywołaniem zipOut.putNextEntry(). W przeciwnym razie wystąpi więcej wyjątków, jeśli przekroczysz atrybut size, zapisując zbyt wiele bajtów w strumieniu wyjściowym. Wygląda na to, że specyfikacje ZIP mówią, że jeśli piszesz ZAPISANE dane, to przed danymi musisz napisać nagłówek [który zawiera CRC-32 i długość] "z góry", stąd interfejs API języka Java wymagający ustawienia przed nim można uruchomić, ponieważ zasadniczo obsługuje on tylko przesyłanie strumieniowe do końcowego pliku zip.


12
2017-11-30 22:23



DEFLATED + Level (0) spowodowały, że mój przypadek ... KAŻDEGO SPRĘŻONEGO PLIKU (A BIT) WIĘKSZY NIŻ PLIK ŹRÓDŁA: O Jestem prawie pewny, że DEFLATED-0 różni się od SKLEPU: / - Andrea Ligios
DEFLATED-0 i STORE moc być różne, ale mają ten sam cel - plik zip zawierający nieskompresowane dane. Nie oczekuję, że któraś z metod wypisze plik równy rozmiarowi do pliku źródłowego. Jednak w pytaniu, Keya miał problemy z używaniem metody STORE, ze względu na wstępne przetwarzanie wymagane do uzyskania wymaganych argumentów. Jeśli chcesz skompresowany plik mniejszy niż plik źródłowy, użyj innej wartości w setLevel () - ale nie o to pytało. - PMorganCA


Musisz użyć STORED metoda, ale wymaga to ustawienia size, compressedSize i crc32 właściwości odpowiadającego ZipEntry zanim będziesz mógł zadzwonić putNextEntry na ZipOutputStream. Możesz wstępnie obliczyć CRC-32 za pomocą a Crc32OutputStream.


7
2018-05-03 10:56



Dzięki, wydajesz się być poprawny, ale czy to jest udokumentowane w dowolnym miejscu? - AlexWien
Jest określony w specyfikacji formatu plików ZIP na pkware.com/documents/casestudies/APPNOTE.TXT . - Christian Schlichtherle
@AlexWien Błąd zostanie zgłoszony przez ZipOutputStream jeśli nie ... na szczęście dostał dobry komunikat o błędzie. - Christophe Roussy


FYI:

W źródle JDK metody [java.util.zip.ZipOutputStream.setLevel (int)]:

public void setLevel(int level) {
    def.setLevel(level);
}

Po prostu przekierowuje ustawienie poziomu kompresji do zmiennej field [def], która jest instancją [java.util.zip.Deflater].

Oraz w kodzie źródłowym klasy [java.util.zip.Deflater]:

/**
 * Compression level for no compression.
 */
public static final int NO_COMPRESSION = 0;

/**
 * Compression level for fastest compression.
 */
public static final int BEST_SPEED = 1;

/**
 * Compression level for best compression.
 */
public static final int BEST_COMPRESSION = 9;

/**
 * Default compression level.
 */
public static final int DEFAULT_COMPRESSION = -1;

Myślę więc, że będzie bardziej czytelny, jeśli użyjesz stałej wartości [Deflater.NO_COMPRESSION]:

zipOut.setMethod(ZipOutputStream.DEFLATED);
zipOut.setLevel(Deflater.NO_COMPRESSION);

5
2017-10-23 02:48