当前位置: 首页 > 知识库问答 >
问题:

java.io.EOFException:在尝试资源中使用ByteArrayOutputStream时,ZLIB输入流意外结束

华英睿
2023-03-14

我试图读取字节数组的内容创建gzip一个对象,但是当我试图解压缩字节数组的内容我得到一个错误声明:java.io.EOFException:意外结束ZLIB输入流

我试图使用java的try with resources习惯用法来管理流资源,同时压缩和解压缩一个对象,但是如果我将ByteArrayOutputStreamhtml" target="_blank">添加到try with resources块中,另一个流ObjectOutputStream将无法关闭。

我检查了ByteArrayOutputStream的实现,它扩展了AutoCloseable接口,即使其close本身没有执行任何工作,也不应该干扰其他资源的关闭。

我试图压缩对象的代码:

    //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);
        }

    }

在这些返回中,CompressedObjectWitByteArray外部和返回CompressedObjectWitExpl郊外似乎返回了一个字节数组,我可以使用下面的解压缩方法,但是在解压缩之前使用returCompressedObject最终会抛出异常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)为何表现不正常,并关闭了流。

在搜索文档时,我没有找到任何地方提到我们不应该在try with resources中使用ByteArrayOutputStream。

任何帮助理解这种行为的原因是感激。

共有2个答案

戚正业
2023-03-14

当您将OutputStream转换为byteArray时,它期望它被关闭。在第三种情况下,您在调用out.toByteArray()之前显式关闭ObjectOutputStream,这是完全有意义的。在第二种情况下,您将out.toByteArray()移到了try-cat-out之外,并在try-with资源块中定义了ObjectOutputStream,当try块结束时,它会关闭ObjectOutputStream。因此,当您调用out.toByteArray()时,ObjectOutputStream已经关闭,因此不再出现问题。

我仍然建议您采用第3种方法或将整个代码包装在另一个try-get块中,并在try-with-资源块中定义ByteArrayOutputStream。因此,此蒸汽将在返回时关闭。

涂选
2023-03-14

我试图理解返回压缩对象(returnCompressedObject)为何表现不正常,并关闭了流。

它失败是因为GZIPOutputStream有内部缓冲区,该缓冲区没有被刷新。通过关闭它,您强制流执行任何最终操作并写出任何剩余字节。如果不关闭它,您将丢失一些数据,因此出现ZLIB输入流消息的意外结束。

 类似资料:
  • 问题内容: 有什么问题或。请阅读以下代码(或运行它,看看会发生什么): 它创建一个文件,通过GZIP 写入单个字节格式,并以相同格式读取同一文件中的字节。 这就是我运行的内容: 由于某些原因,阅读线似乎走错了路。 我搜索了该错误,并发现了一些有关Oracle的错误报告,这些错误报告是在2007-2010年间发布的。因此,我认为该错误仍然存​​在,但是我不确定我的代码是否正确,因此让我在此处发布并听

  • 我认为流API在这里是为了使代码更易于阅读。我觉得有点烦。流接口扩展了java。lang.AutoCloseable接口。 因此,如果你想正确地关闭流,你必须使用try-with资源。 清单1.不是很好,流没有关闭。 清单2.使用2嵌套try 清单3。当map返回流时,必须关闭stream()和map()函数。 我举的例子毫无意义。为了示例,我将jpg图像的路径替换为整数。但不要让这些细节分散你的

  • 我使用fetch简单地从虚拟apiendpoint获取数据,但当我在函数中添加配置时,我得到了一个意外的输入错误结束。 这工作得很好,控制台记录了200个项目的数组 但当我将configs作为参数添加时,它会显示和错误。 错误: 和

  • 问题内容: 我正在使用fetch()从api服务器获取数据。我的错误如下所示: 你能告诉我我在做什么错。 问题答案: 一种用于响应请求到跨源资源具有“不透明”的响应类型。如果在尝试将响应转换为JSON之前记录响应,您将看到一种“不透明”的类型。 不透明类型被列为“严重受限”。 不透明的已过滤响应是已过滤的响应,其类型为“不透明”,URL列表为空列表,状态为0,状态消息为空字节序列,标头列表为空,主

  • 我使用fetch()从api服务器获取数据。我的错误是这样的: 你能告诉我我做错了什么吗。

  • 我正在尝试解析从Movie DB返回的JSON数据。我收到一个错误,告诉我我收到以下错误: MovieReq.Open('get','https://api.themoviedb.org/3/movie/299537?api_key=',false); 我还有其他XMLHttpRequests可以很好地返回JSON数据。这些请求使用API的discover函数。 这是产生问题的函数 {“成人”:f