avro序列化文件

  • 向文件中写入数据(序列化)
  • 从文件中读取数据(反序列化)

简介

  • 它可以提供:
  • 丰富的数据结构类型
  • 快速可压缩的二进制数据形式
  • 存储持久数据的文件容器
  • 远程过程调用RPC
  • 简单的动态语言结合功能,Avro和动态语言结合后,读写数据文件和使用RPC协议都不需要生成代码,而代码生成作为一种可选的优化只值得在静态类型语言中实现。
  • Avro依赖于模式(Schema)。Avro数据的读写操作是很频繁的,而这些操作都需要使用模式,这样就减少写入每个数据资料的开销,使得序列化快速而又轻巧。这种数据及其模式的自我描述方便于动态脚本语言的使用。
  • 当Avro数据存储到文件中时,它的模式也随之存储,这样任何程序都可以对文件进行处理。如果需要以不同的模式读取数据,这也很容易解决,因为两个模式都是已知的。
  • 当在RPC中使用Avro时,服务器和客户端可以在握手连接时交换模式。服务器和客户端有着彼此全部的模式,因此相同命名字段、缺失字段和多余字段等信息之间通信中需要解决的一致性问题就可以容易解决
  • 还有,Avro模式是用JSON(一种轻量级的数据交换模式)定义的,这样对于已经拥有JSON库的语言可以容易实现。
  • Avro提供着如Thrift和Protocol Buffers等系统相似的功能,但是在一些基础方面还是有区别的,主要是:
    • 动态类型:Avro并不需要生成代码,模式和数据存放在一起,而模式使得整个数据的处理过程并不生成代码、静态数据类型等等。这方便了数据处理系统和语言的构造。
    • 未标记的数据:由于读取数据的时候模式是已知的,那么需要和数据一起编码的类型信息就很少了,这样序列化的规模也就小了。
    • 不需要用户指定字段号:即使模式改变,处理数据时新旧模式都是已知的,所以通过使用字段名称可以解决差异问题
  • ——-[百度百科]

maven 项目的 avro 配置

在 maven 项目中使用 avro 需要在 pom.xml 文件中配置两项内容

  • 添加avro 的依赖:
    <dependency>
        <groupId>org.apache.avro</groupId>
        <artifactId>avro</artifactId>
        <version>1.8.2</version>
    </dependency>
  • 添加 avro 的maven的插件
<build>
    <plugins>
        <plugin>
            <groupId>org.apache.avro</groupId>
            <artifactId>avro-maven-plugin</artifactId>
            <version>1.8.2</version>
            <executions>
                <execution>
                    <!-- maven 指令,生成代码 -->
                    <!-- 通过执行指令  mvn generate-sources 可以生成代码 -->
                    <phase>generate-sources</phase>
                    <goals>
                        <!-- 执行生成 scheme -->
                        <goal>schema</goal>
                    </goals>
                    <configuration>
                        <!-- 生成的依据:scheme 的定义文件 -->
                        <!-- 根据 scheme的定义来生成 java 代码 -->
                        <sourceDirectory>${project.basedir}/src/main/avro/</sourceDirectory>
                        <!-- 生成代码的存放位置 -->
                        <outputDirectory>${project.basedir}/src/main/java/</outputDirectory>
                    </configuration>
                </execution>
            </executions>
        </plugin>
        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-compiler-plugin</artifactId>
            <configuration>
                <source>1.6</source>
                <target>1.6</target>
            </configuration>
        </plugin>
    </plugins>
</build>

> 定义的插件中 <execution></execution>标签可能会报错,可能是因为插件的原因,不影响使用
  • 使用 avro 需要创建模式对象 schema
  • schema 为 JSON 格式的文件,保存的文件的后缀名为 .avsc 例如:

    {
    “type”:”record”,
    “name”:”UserActionLog”,
    “namespace”:”com.zhiyou100.bd17.scheme”,
    “fields”:[
    {“name”:”userName”,”type”:”string”},
    {“name”:”actionType”,”type”:”string”},
    {“name”:”ipAddress”,”type”:”string”},
    {“name”:”gender”,”type”:”int”},
    {“name”:”provience”,”type”:”string”}
    ]
    }

  • 创建模式对象可以通过执行 Maven build 中的语句产生 java 对象

  • 这里写图片描述
    这里写图片描述

代码块

  • 创建两条数据通过序列化写入到文件中

import java.io.File;
import java.io.IOException;

import org.apache.avro.file.DataFileWriter;
import org.apache.avro.io.DatumWriter;
import org.apache.avro.specific.SpecificDatumWriter;

import bd17.scheme.UserActionLog;

public class WriteAsAvro {

    public static void main(String[] args) throws Exception {

        UserActionLog ual1 = new UserActionLog();

        ual1.setActionType("login");
        ual1.setGender(1);
        ual1.setIpAddress("192.168.1.1");
        ual1.setProvience("henan");
        ual1.setUserName("lily");

        UserActionLog ual2 = UserActionLog.newBuilder().setActionType("logout").setGender(0).setIpAddress("192.168.1.2")
                .setProvience("hebie").setUserName("jim").build();

        // 把两条记录写入到文件中(序列化)
        // 把两条记录写入到文件中(序列化)
        // DatumWriter 是一个 接口,需要用它的实现类创建对象
        // 如果创建了实例化对象,则使用  SpecificDatumWriter  来创建对象
        // 如果没有创建实例化对象,则使用 GenericDatumWriter 来创建对象
        DatumWriter<UserActionLog> writer = new SpecificDatumWriter<UserActionLog>();
        DataFileWriter<UserActionLog> fileWriter = new DataFileWriter<UserActionLog>(writer);

        // 创建序列化文件,文件会创建到项目的根目录下
        fileWriter.create(UserActionLog.getClassSchema(), new File("userlogaction.avro"));

        // 写入内容
        fileWriter.append(ual1);
        fileWriter.append(ual2);

        fileWriter.flush();
        fileWriter.close();

    }
}
  • 反序列化,将序列化写出的文件读取出来

import java.io.File;

import org.apache.avro.file.DataFileReader;
import org.apache.avro.io.DatumReader;
import org.apache.avro.specific.SpecificDatumReader;

import bd17.scheme.UserActionLog;

public class ReadFromAvro {

    public static void main(String[] args) throws Exception {

        File file = new File("userlogaction.avro");

        DatumReader<UserActionLog> reader = new SpecificDatumReader<UserActionLog>();

        DataFileReader<UserActionLog> fileReader = new DataFileReader<UserActionLog>(file, reader);

        UserActionLog readUserActionLog = null;

        while(fileReader.hasNext()){

            readUserActionLog = fileReader.next();
            System.out.println(readUserActionLog);
        }
        fileReader.close();
    }
}
  • 编辑的 schema 模式对象的文件可以不通过上述 Maven build 语句产生 java 类的对象,可以直接使用 Schema.Parser 直接创建模式对象的实例
  • 代码实现(序列化)

import java.io.File;

import org.apache.avro.Schema;
import org.apache.avro.file.DataFileWriter;
import org.apache.avro.generic.GenericData;
import org.apache.avro.generic.GenericDatumWriter;
import org.apache.avro.generic.GenericRecord;
import org.apache.avro.io.DatumWriter;

public class AvroWriter {

    private Schema schema;

    // parser 是专门用来把字符串或者 avsc 文件转换成 schema 对象的一个工具类
    private Schema.Parser parser = new Schema.Parser();

    public AvroWriter() {
        super();
    }

    // 构造方法,初始化schema, 根据要序列化的数据而定
    public AvroWriter(String schameFile) throws Exception {

        this.schema = parser.parse(new File(schameFile));
    }

    public void writeData(GenericRecord record) throws Exception{

        // 这里没有创建 schema 的模式对象,需要使用 GenericDatumWriter 来实例化对象
        DatumWriter<GenericRecord> writer = new GenericDatumWriter<GenericRecord>();
        DataFileWriter<GenericRecord> fileWriter = new DataFileWriter<GenericRecord>(writer);

        fileWriter.create(schema, new File("noobjuesrlogaction.avro"));
        fileWriter.append(record);
        fileWriter.flush();
    }

    public static void main(String[] args) throws Exception {

        // 用模式文件的位置作为参数初始化 writer 序列化类
        AvroWriter avroWriter = new AvroWriter("src/main/avro/user_action_log.avsc");

        // 创建 GenericRecord 对象
        GenericRecord record = new GenericData.Record(avroWriter.schema);
        record.put("userName", "jim");
        record.put("actionType", "new_tweet");
        record.put("ipAddress", "192.168.1.3");
        record.put("gender", 0);
        record.put("provience", "yunnan");

        avroWriter.writeData(record);

    }
}
  • 反序列化

import java.io.File;

import org.apache.avro.file.DataFileReader;
import org.apache.avro.generic.GenericDatumReader;
import org.apache.avro.generic.GenericRecord;
import org.apache.avro.io.DatumReader;

public class AvroReader {

    public static void main(String[] args) throws Exception {

        DatumReader<GenericRecord> reader = new GenericDatumReader<GenericRecord>();
        DataFileReader<GenericRecord> fileReader = new DataFileReader<GenericRecord>(new File("noobjuesrlogaction.avro"), reader);

        GenericRecord record = null;

        while(fileReader.hasNext()) {

            record = fileReader.next();
            System.out.println(record);
        }
        fileReader.close();
    }
}

Logo

权威|前沿|技术|干货|国内首个API全生命周期开发者社区

更多推荐