#java #compression #zip #deflate
#java #сжатие #zip #выкачать
Вопрос:
Следующий код основан на примере, приведенном в javadocs для java.util.zip.Deflater. Единственные изменения, которые я внес, — это создать массив байтов с именем dict, а затем установить словарь как для экземпляров Deflater, так и для Inflater, используя метод setDictionary(byte[]).
Проблема, которую я вижу, заключается в том, что когда я вызываю Inflater.setDictionary() с точно таким же массивом, который я использовал для Deflater, я получаю исключение IllegalArgumentException.
Вот код, о котором идет речь:
import java.util.zip.Deflater;
import java.util.zip.Inflater;
public class DeflateWithDictionary {
public static void main(String[] args) throws Exception {
String inputString = "blahblahblahblahblah??";
byte[] input = inputString.getBytes("UTF-8");
byte[] dict = "blah".getBytes("UTF-8");
// Compress the bytes
byte[] output = new byte[100];
Deflater compresser = new Deflater();
compresser.setInput(input);
compresser.setDictionary(dict);
compresser.finish();
int compressedDataLength = compresser.deflate(output);
// Decompress the bytes
Inflater decompresser = new Inflater();
decompresser.setInput(output, 0, compressedDataLength);
decompresser.setDictionary(dict); //IllegalArgumentExeption thrown here
byte[] result = new byte[100];
int resultLength = decompresser.inflate(result);
decompresser.end();
// Decode the bytes into a String
String outputString = new String(result, 0, resultLength, "UTF-8");
System.out.println("Decompressed String: " outputString);
}
}
Если я попытаюсь выкачать те же сжатые байты без настройки словаря, я не получу ошибки, но возвращаемый результат равен нулю байт.
Есть ли что-то особенное, что мне нужно сделать, чтобы использовать пользовательский словарь с Deflater / Inflater?
Ответ №1:
Я действительно понял это при формулировании вопроса, но подумал, что мне все равно следует опубликовать вопрос, чтобы другие могли извлечь выгоду из моей борьбы.
Оказывается, вам нужно вызвать inflate () один раз после установки входных данных, но перед установкой словаря. Возвращаемое значение будет равно 0, и вызов needsDictionary() вернет значение true. После этого вы можете установить словарь и снова вызвать inflate.
Исправленный код выглядит следующим образом:
import java.util.zip.Deflater;
import java.util.zip.Inflater;
public class DeflateWithDictionary {
public static void main(String[] args) throws Exception {
String inputString = "blahblahblahblahblah??";
byte[] input = inputString.getBytes("UTF-8");
byte[] dict = "blah".getBytes("UTF-8");
// Compress the bytes
byte[] output = new byte[100];
Deflater compresser = new Deflater();
compresser.setInput(input);
compresser.setDictionary(dict);
compresser.finish();
int compressedDataLength = compresser.deflate(output);
// Decompress the bytes
Inflater decompresser = new Inflater();
decompresser.setInput(output, 0, compressedDataLength);
byte[] result = new byte[100];
decompresser.inflate(result);
decompresser.setDictionary(dict);
int resultLength = decompresser.inflate(result);
decompresser.end();
// Decode the bytes into a String
String outputString = new String(result, 0, resultLength, "UTF-8");
System.out.println("Decompressed String: " outputString);
}
}
Это кажется очень нелогичным и неуклюжим с точки зрения дизайна API, поэтому, пожалуйста, просветите меня, если есть какие-либо лучшие альтернативы.
Комментарии:
1. Причина
needsDictionary()
заключается в том, что формат zlib позволяет использовать разные словари в одном приложении и указывает в заголовке файла контрольную сумму Adler32-словаря. Чтобы прочитать этот заголовок (и разрешить приложению на стороне распаковки выбрать правильный словарь), необходим первый вызовinflate
.2. Когда я это делал, мне нужно было установить словарь перед inflate (), что, как ни странно, имеет смысл. Итак, что-то не так в вашем примере…