首页 > 解决方案 > java.io.IOException:从文件读取 Avro 时不是数据文件

问题描述

以下代码用于序列化数据。

        ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
        BinaryEncoder binaryEncoder =
            EncoderFactory.get().binaryEncoder(byteArrayOutputStream, null);

        DatumWriter<GenericRecord> datumWriter = new GenericDatumWriter<>(data.getSchema());
        datumWriter.setSchema(data.getSchema());
        datumWriter.write(data, binaryEncoder);

        binaryEncoder.flush();
        byteArrayOutputStream.close();

        result = byteArrayOutputStream.toByteArray();

我使用了以下命令

FileUtils.writeByteArrayToFile(new File("D:/sample.avro"), data);

将 avro 字节数组写入文件。但是当我尝试阅读相同的内容时

 File file = new File("D:/sample.avro");
        try {
          dataFileReader = new DataFileReader(file, datumReader);

        } catch (IOException exp) {
          System.out.println(exp);
          System.exit(1);
       }

它抛出异常

java.io.IOException: Not a data file.
    at org.apache.avro.file.DataFileStream.initialize(DataFileStream.java:105)
    at org.apache.avro.file.DataFileReader.<init>(DataFileReader.java:97)
    at org.apache.avro.file.DataFileReader.<init>(DataFileReader.java:89)

这里发生了什么问题。我提到了另外两个类似的stackoverflow问题thisthis,但对我没有太大帮助。有人可以帮我理解这一点。

标签: javaavrofilereader

解决方案


实际数据以 Avro 二进制格式编码,但通常传递的不仅仅是编码数据。

大多数人对“avro 文件”的看法是一种格式,其中包括标题(其中包含诸如 writer 架构之类的内容)以及实际数据:https ://avro.apache.org/docs/current/spec.html#对象+容器+文件。avro 文件的前四个字节应该是 b"Obj1" 或 0x4F626A01。您收到的错误是因为您尝试作为数据文件读取的二进制文件不是以标准魔术字节开头。

另一种标准格式是单对象编码:https ://avro.apache.org/docs/current/spec.html#single_object_encoding 。这种类型的二进制格式应该以 0xC301 开头。

但如果我不得不猜测,您拥有的二进制文件可能只是没有任何类型的标头信息的原始序列化数据。尽管如果不知道您拥有的字节数组是如何创建的,则很难确定。


推荐阅读