Я был укушен этим в некоторых модульных тестах.
Я хочу распаковать некоторые сжатые ZLIB данные, используя Inflater , где длина необработанных данных известна заранее.
Это (прямолинейно) работает как положено
/*
* Decompresses a zlib compressed buffer, with given size of raw data.
* All data is fed and inflated in full (one step)
*/
public static byte[] decompressFull(byte[] comp, int len) throws Exception {
byte[] res = new byte[len]; // result (uncompressed)
Inflater inf = new Inflater();
inf.setInput(comp);
int n = inf.inflate(res, 0, len);
if (n != len)
throw new RuntimeException("didn't inflate all data");
System.out.println("Data done (full). bytes in :" + inf.getBytesRead()
+ " out=" + inf.getBytesWritten()
+ " finished: " + inf.finished());
// done - the next is not needed, just for checking...
//try a final inflate just in case (might trigger ZLIB crc check)
byte[] buf2 = new byte[6];
int nx = inf.inflate(buf2);//should give 0
if (nx != 0)
throw new RuntimeException("nx=" + nx + " " + Arrays.toString(buf2));
if (!inf.finished())
throw new RuntimeException("not finished?");
inf.end();
return res;
}
Теперь сжатый ввод может входить в порции произвольного размера.Следующий код эмулирует случай, когда сжатый вход подается полностью, за исключением последних 4 байтов, а затем остальные байты подаются по одному.(Как я понимаю, последние 4 или 5 байтов потока zlib не нужны для распаковки полных данных, но они необходимы для проверки целостности - Adler-32 CRC).
public static byte[] decompressBytexByte(byte[] comp, int len) throws Exception {
byte[] res = new byte[len]; // result (uncompressed)
Inflater inf = new Inflater();
inf.setInput(comp, 0, comp.length - 4);
int n = inf.inflate(res, 0, len);
if (n != len)
throw new RuntimeException("didn't inflate all data");
// inf.setInput(comp, comp.length-4,4);
// !!! works if I uncomment the line befor and comment the next for
for (int p = comp.length - 4; p < comp.length; p++)
inf.setInput(comp, p, 1);
System.out.println("Data done (decompressBytexByte). bytes in :" + inf.getBytesRead()
+ " out=" + inf.getBytesWritten() + " finished: " + inf.finished());
// all data fed... try a final inflate (might -should?- trigger ZLIB crc check)
byte[] buf2 = new byte[6];
int nx = inf.inflate(buf2);//should give 0
if (nx != 0)
throw new RuntimeException("nx=" + nx + " " + Arrays.toString(buf2));
if (!inf.finished())
throw new RuntimeException("not finished?");
inf.end();
return res;
}
Ну, это не работает для меня (Java 1.8.0_181).Воздуходувка не закончена, проверка Adler CRC не выполнена, кажется;более того: кажется, что байты не передаются в инфлятор.
Еще более странно: это работает, если завершающие 4 байта передаются за один вызов.
Вы можете попробовать это здесь: https://repl.it/@HernanJJ/Inflater-Test
Даже странные вещи случаются, когда я подаю весь ввод по одному байту за раз: иногда строка int nx= inf.inflate(buf2);//should give 0
возвращает ненулевое значение (когда все данные уже заполнены).
Это ожидаемое поведение?Я что-то упустил?