Как создать несжатый архив ZIP в Java
Я использую пакет утилиты Zip для Java и хотел знать, как создать zip файл без сжатия вообще. Установка уровня на 0 не помогает. Правильно ли это?
Кроме того, когда я использовал метод STORED
, он выдает следующее исключение:
java.util.zip.ZipException: STORED entry missing size, compressed size, or crc-32
Я могу установить размер, но теперь вызывается следующее исключение:
java.util.zip.ZipException: invalid entry crc-32
Я просто следую всем примерам, доступным при поиске в Интернете, и я не могу это понять, я думаю. Было бы здорово, если бы кто-то помог мне в этом и предложит мне исправить проблему, которую я мог бы делать.
Ответы
Ответ 1
Я обожаю решение aperkins (с момента удаления), но я знаю, почему это сработало. Линия (которая с тех пор была исправлена в его ответе)
zipOut.setLevel(ZipOutputStream.STORED); // accidentally right
использовало статическое значение ZipOutputStream.STORED
, которое по совпадению равно 0
. Так что эта строка делает настройку уровня, используемого методом DEFLATED по умолчанию, на нулевое сжатие (это, очевидно, то, что вы хотите сделать, но случилось только с удачей). Чтобы получить то, что вы хотите явно и безопасно, используйте вместо этого:
zipOut.setMethod(ZipOutputStream.DEFLATED); // this line optional
zipOut.setLevel(0);
или
zipOut.setLevel(Deflater.NO_COMPRESSION);
Если вы используете
zipOut.setMethod(ZipOutputStream.STORED);
zipOut.setLevel(Deflater.NO_COMPRESSION);
вы, вероятно, получите Исключение, которое Keya отметил в исходном вопросе. Я считаю, что Christian Schlichtherle прав; вы получаете Исключения, потому что вы не устанавливаете CRC в записи. Это связано с тем, что для использования метода STORED вам необходимо сначала прочитать весь файл записи или найти другой способ установить размер, сжатый размер (должен быть равен) и CRC перед вызовом zipOut.putNextEntry()
. В противном случае вы столкнетесь с дополнительными исключениями, если вы превысите атрибут размера, записав слишком много байтов в выходной поток. Похоже, что в спецификациях ZIP говорят, что если вы записываете STORED-данные, тогда перед самими данными он должен записать заголовок [который включает в себя CRC-32 и длину] перед фронтом, поэтому API-интерфейс Java, требующий их, должен быть установлен перед ним может начаться, поскольку он в основном поддерживает только потоковое воспроизведение до последнего zip файла.
Ответ 2
Вам нужно использовать метод STORED
, но для этого нужно установить свойства size
, compressedSize
и crc32
соответствующего ZipEntry
, прежде чем вы сможете вызвать putNextEntry
на ZipOutputStream
, Вы можете предварительно скопировать CRC-32 с помощью Crc32OutputStream
.
Ответ 3
FYI:
В JDK Источник метода [java.util.zip.ZipOutputStream.setLevel(int)]:
public void setLevel(int level) {
def.setLevel(level);
}
Он просто перенаправляет настройку уровня сжатия на переменную поля [def], которая является экземпляром [java.util.zip.Deflater].
И в исходном коде класса [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;
Итак, я думаю, что это будет более читаемо, если вы используете постоянное значение [Deflater.NO_COMPRESSION]:
zipOut.setMethod(ZipOutputStream.DEFLATED);
zipOut.setLevel(Deflater.NO_COMPRESSION);