整套大数据学习资料(视频+笔记)百度网盘无门槛下载:http://www.edu360.cn/news/content?id=3377

4.4.2内存中的序列化和反序列化

hadoop 花牛 9℃ 0评论

Avro为序列化和反序列化提供了API,如果想把Avro集成到现有系统(比如已定义帧格式的消息系统),这些API函数就很有用。其他情况,请考虑使用Avro的数据文件格式。

让我们写一个Java程序从数据流读/写Avro数据。首先以一个简单的Avro 模式为例,它用于表示以记录形式出现的一对字符串:

{

"type": "record",

"name": "StingPair",

"doc": "A pair of strings.",

"fields":[

{"name": "left", "type": "string"},

{"name": "right", "type": "string"}

]

}

如果这一模式存储在类路径下一个名为StringPair.avsc的文件中(.avsc是 Avro模式文件的常用扩展名),我们可以通过下列两行代码进行加载:

Schema.Parser parser = new Schema.Parser();
Schema schema = parser.parse(getClass().getResourceAsStream("StringPair.avsc"));

我们可以使用以下通用API新建一个Avro记录的实例:

GenericRecord datum = new GenericData.Record(schema);
datum.put("left", new Utf8("L"));
datum.put("right", new Utf8(",R"));

注意,我们为记录的String字段构造了一个Avro Utf 8实例。

接下来,我们将记录序列化到输出流中:

ByteArrayOutputStream out = new ByteArrayOutputStream();
DatumWriter<GenericRecord> writer = new GenericDatumWriter<GenericRecord>(schema);
Encoder encoder = EncoderFactory.get().binaryEncoder(out, null); 
writer.write(datum, encoder);
encoder.flush();
out.close();

这里有两个重要的对象:DaturnWriter和Encoder。DatumWriter对象将数据对象翻译成Encoder对象可以理解的类型,然后由后者写到输出流。这里,我们使用GenericDatumWriter对象,它将GenericRecord字段的值传递给Encoder对象。我们将null传给encoder工厂,因为我们这里没有重用先前构建的encoder。

在本例中,只有一个对象被写到输出流,但如果需要写若干个对象,我们可以调用write()方法,然后再关闭输入流。

需要向GenericDatumWriter对象传递模式,因为它要根据模式来确定将数据对象中的哪些数值写到输出流。在我们调用writer的write()方法后,刷新encoder,然后关闭输出流。

我们可以使用反向的处理过程从字节缓冲区中读回对象:

DatumReader<GenericRecord> reader = new GenericDatumReader <GenericRecord>(schema);
Decoder decoder = DecoderFactory.get().createBinaryDecoder(out.toByteArray(),null);
GenericRecord result = reader.read(null, decoder);
assertThat(result.get("left").toString(), is("L"));
assertThat(result.get("right").toString(), is("R"));

我们需要传递空值(null)并调用binaryDecoder()和read()方法,因为这里没有重用对象(分别是decoder或记录)。

由result.get("left")和 result.get("right")的输出对象是 Utf8类型,因此我们需要通过调用toString()方法将它们转型为java String 类型。

特定API

让我们现在来看看使用特定API的等价代码。通过使用Avro的Maven插件编译模式,我们可以根据模式文件生成StringPair类。以下是与Maven Project Object Model(POM)相关的部分:

<project>
  ...
  <build>
    <plugins>
      <plugin>
        <groupId>org.apache.avro</groupId>
        <artifactId>avro-maven-plugin</artifactId>
        <version>${avro.version}</version>
        <executions>
          <execution>
            <id>schemas</id>
            <phase>generate-sources</phase>
            <goals>
              <goal>schema</goal>
            </goals>
            <configuration>
              <includes>
                <include>StringPair.avsc</include>
              </includes>
              <sourceDirectory>src/main/resources</sourceDirectory>
              <outputDirectory>${project.build.directory}/generated-sources/java </outputDirectory>
            </configuration>
          </execution>
        </executions>
      </plugin>
    </plugins>
  </build>
  ...
</project>

作为Maven的替代,你可以使用Avro的Ant任务org.apache.avro.specific.SchemaTask或者Avro的命令行工具针对模式生成Java代码。

可以从http://avro.apache.org/releases.html下载avro的源文件和二进制文件。键入命令java -jar avro-tools-*.jar可以获得使用指南。

在序列化和反序列化的代码中,我们构建一个StringPair实例来替代GenericRecord对象(使用SpecificDatumWriter类将该对象写入数据流)并使用SpecificDatumReader类读回数据:

StringPair datum = new StringPair();
datum.left = "L";
datum.right = "R";
ByteArrayOutputStream out = new ByteArrayOutputStneam();
DatumWriter<StringPair> writer =new SpecificDatumWriter<StringPair>(StringPair.class);
Encoder encoder = EncoderFactory.get().binaryEncoder(out, null);
writer.write(datum, encoder);
encoder.flush();
out.close();
DatumReader<StringPair> reader =new SpecificDatumReader<StringPair>(StringPair.class);
Decoder decoder = DecoderFactory.get().biriaryDecoder(out.toByteArray(), null);
StringPair result = reader.read(null, decoder);
assertThat(result.left.toString(), is("L"));
assertThat(result.right.toString(), is("R"));

从Avro 1.6.0版本开始,生成的Java代码中包含有get()和set()方法,不用再写datum.setLeft("L")和 result.getLeft()方法。

转载请注明:全栈大数据 » 4.4.2内存中的序列化和反序列化

喜欢 (0)or分享 (0)
发表我的评论
取消评论

表情

Hi,您需要填写昵称和邮箱!

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址