如何将多个Avro对象写入ByteArrayOutputStream?代码反序列化失败排查
问题:Avro序列化多个对象到ByteArrayOutputStream后客户端无法反序列化?
Avro官方文档中写入多个对象到文件的示例代码如下:
DatumWriter<User> userDatumWriter = new SpecificDatumWriter<User>(User.class); DataFileWriter<User> dataFileWriter = new DataFileWriter<User>(userDatumWriter); dataFileWriter.create(user1.getSchema(), new File("users.avro")); dataFileWriter.append(user1); dataFileWriter.append(user2); dataFileWriter.append(user3); dataFileWriter.close();
我希望实现类似功能,但将数据写入ByteArrayOutputStream,于是编写了如下代码:
ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); Encoder encoder = EncoderFactory.get().binaryEncoder(outputStream, null); DatumWriter<MyData> myDataDatumWriter = new SpecificDatumWriter<>(MyData.getClassSchema()); myDataDatumWriter.write(myData1, encoder); encoder.flush(); myDataDatumWriter.write(myData2, encoder); encoder.flush();
将该输出流中的数据作为HTTP响应发送后,客户端无法反序列化,提示格式不可识别。请问这段代码存在什么问题?
解答
你的代码核心问题是:直接使用DatumWriter结合Encoder写入的是原始Avro二进制数据,这种数据仅包含单个对象的序列化内容,没有Avro容器文件必需的元信息(比如schema定义、文件头标识、同步标记等)。而客户端反序列化时,通常期望的是标准Avro容器文件格式(也就是官方示例中DataFileWriter生成的格式),缺少这些元信息会导致客户端无法识别数据格式。
DataFileWriter的作用就是封装Avro容器格式的生成逻辑:它会先写入文件头(包含schema、文件魔数等),然后将每个对象的序列化数据按规范写入,同时插入同步标记,这样客户端可以正确识别并反序列化多个对象。
正确的实现方式应该是用DataFileWriter写入ByteArrayOutputStream,而不是直接使用Encoder,代码示例如下:
ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); DatumWriter<MyData> myDataDatumWriter = new SpecificDatumWriter<>(MyData.getClassSchema()); DataFileWriter<MyData> dataFileWriter = new DataFileWriter<>(myDataDatumWriter); // 创建容器文件(写入schema等元信息) dataFileWriter.create(MyData.getClassSchema(), outputStream); // 追加多个对象 dataFileWriter.append(myData1); dataFileWriter.append(myData2); // 关闭writer,确保所有数据写入完成 dataFileWriter.close(); // 后续可以将outputStream转换为字节数组用于HTTP响应 byte[] avroData = outputStream.toByteArray();
这样生成的字节数据是标准的Avro容器格式,客户端可以正常识别并反序列化其中的多个对象。
内容的提问来源于stack exchange,提问作者user8473984
相关产品推荐
相关产品推荐

