java.io.EOFException: неожиданный конец входного потока ZLIB при использовании ByteArrayOutputStream в try-with-resources - PullRequest
1 голос
/ 05 июня 2019

Я пытаюсь прочитать содержимое байтового массива, созданного с помощью gzip-объекта, однако, когда я пытаюсь распаковать содержимое байтового массива, я получаю сообщение об ошибке: java.io.EOFException: неожиданный конец входного потока ZLIB

Я пытаюсь использовать идиому try-with-resources из java для управления ресурсами потока при сжатии и распаковке объекта, однако, если я добавлю ByteArrayOutputStream в блок try-with-resources, другой поток ObjectOutputStream не сможетclose.

Я проверил реализацию ByteArrayOutputStream, он расширяет интерфейс AutoCloseable, и хотя его закрытие не выполняет никакой работы как таковое, оно не должно мешать закрытию других ресурсов.

Код, который я пытался сжать для объекта:

    //This fails
    public static byte[] returnCompressedObject(Object object) {
        try(ByteArrayOutputStream out = new ByteArrayOutputStream();
            GZIPOutputStream gzOut = new GZIPOutputStream(out);
            ObjectOutputStream objOut = new ObjectOutputStream(gzOut)) {
            objOut.writeObject(object);
            return out.toByteArray();
        } catch (IOException e) {
            throw new RuntimeException("Error converting object to bytes ", e);
        }
    }

    //This works with ByteArrayOutputStream moved out of try-with-resources block
    public static byte[] returnCompressedObjectWithByteArrayOutside(Object object) {
        //ByteArrayOutputStream moved out of try-with-resources block
        ByteArrayOutputStream out = new ByteArrayOutputStream();
        try(GZIPOutputStream gzOut = new GZIPOutputStream(out);
            ObjectOutputStream objOut = new ObjectOutputStream(gzOut)) {
            objOut.writeObject(object);
        } catch (IOException e) {
            throw new RuntimeException("Error converting object to bytes ", e);
        }
        return out.toByteArray();
    }

    //This works with explicit close being called on ObjectOutputStream
    public static byte[] returnCompressedObjectWithExplicitClose(Object object) {
        try(ByteArrayOutputStream out = new ByteArrayOutputStream();
            GZIPOutputStream gzOut = new GZIPOutputStream(out);
            ObjectOutputStream objOut = new ObjectOutputStream(gzOut)) {
            objOut.writeObject(object);
            //Explicit close being called on ObjectOutputStream
            objOut.close();
            return out.toByteArray();
        } catch (IOException e) {
            throw new RuntimeException("Error converting object to bytes ", e);
        }

    }

Из этих returnCompressedObjectWithByteArrayOutside и returnCompressedObjectWithExplicitClose кажется, что я возвращаю массив байтов, который я могу использовать нижераспаковать метод, ноиспользование returnCompressedObject до того, как разархивирование завершится выдачей исключения java.io.EOFException: неожиданный конец входного потока ZLIB во время распаковки Метод, использованный для распаковки:

    public static String decompressUsingGZip(byte[] object) {
        try(ByteArrayInputStream messageInputStream = new ByteArrayInputStream(object);
            GZIPInputStream gzipStream = new GZIPInputStream(messageInputStream);
            InputStreamReader inputStreamReader = new InputStreamReader(gzipStream, StandardCharsets.UTF_8);
            BufferedReader reader = new BufferedReader(inputStreamReader)){
            return reader.lines().collect(Collectors.joining());
        } catch (IOException e) {
            throw new RuntimeException("Error uncompressing object", e);
        }
    }

Япытаясь понять , почему returnCompressedObject не работает должным образом и закрывает потоки.

При поиске документации я не нашел места, где он находитсяупомянул, что мы не должны использовать ByteArrayOutputStream в try-with-resources.

Любая помощь в понимании причины такого поведения приветствуется.

Ответы [ 2 ]

1 голос
/ 05 июня 2019

Когда вы конвертируете OutputStream в byteArray, он ожидает, что он будет закрыт. В третьем случае вы явно закрываете ObjectOutputStream перед вызовом out.toByteArray () , что имеет смысл. Во втором случае вы переместили out.toByteArray () за пределы try-catch и определили ObjectOutputStream в блоке try-with-resource, который закрывает ObjectOutputStream после завершения блоков try. Поэтому, когда вы вызываете out.toByteArray (), ObjectOutputStream уже был закрыт, поэтому проблем больше нет.

Я по-прежнему предлагаю вам использовать третий подход или обернуть весь код в другой блок try-catch и определить ByteArrayOutputStream в блоке try-with-resource. Так что этот пар закроется при возвращении.

1 голос
/ 05 июня 2019

Я пытаюсь понять, почему returnCompressedObject не работает должным образом и закрывает потоки.

Не удается, потому что GZIPOutputStream имеет внутренний буфер, который не очищается,Закрывая его, вы заставляете поток выполнять последние операции и записывать оставшиеся байты.Если вы не закроете его, вы потеряете некоторые данные, следовательно, сообщение Unexpected end of ZLIB input stream.

...