序列化:把数据加工成特定的格式
反序列化:把特定格式的数据解析成对象

Avro提供了两种序列化和反序列化的方式:一种是通过Schema文件来生成代码的方式,一种是不生成代码的通用方式,这两种方式都需要构建Schema文件。
Avro在序列化时可以通过指定编码器,将数据序列化成标准的JSON格式,也可以序列化成二进制格式。
Avro支持两种序列化编码方式:二进制编码和JSON编码,使用二进制编码会高效序列化,并且序列化后得到的结果会比较小。而JSON一般用于调试系统或是基于WEB的应用。对Avro数据序列化/反序列化时都需要对模式以深度优先(Depth-First),从左到右(Left-to-Right)的遍历顺序来执行。

下面通过具体的例子来进行演示:

项目框架

创建一个Maven项目:

  • 在pom.xml文件中添加依赖:
<dependency><groupId>junit</groupId><artifactId>junit</artifactId><version>4.12</version><scope>test</scope>
</dependency><dependency><groupId>org.apache.avro</groupId><artifactId>avro</artifactId><version>1.9.1</version>
</dependency>
  • 在pom.xml文件中配置插件:
 <plugins><plugin><groupId>org.apache.avro</groupId><artifactId>avro-maven-plugin</artifactId><version>1.9.1</version><executions><execution><phase>generate-sources</phase><goals><goal>schema</goal></goals><configuration>
<sourceDirectory>${project.basedir}/src/main/resources/</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><encoding>utf-8</encoding><source>1.8</source><target>1.8</target></configuration></plugin></plugins>
  • 在resources目录下定义模式文件dept.avsc
{"namespace":"com.hc.bean",
"type":"record",
"name":"Dept",
"fields":[{"name":"deptno","type":"int"},{"name":"dname","type":"string"},{"name":"loc","type":"string"}
]
}

使用生成的代码(类)进行序列化和反序列化

第一步:根据schema自动生成对应的Dept类

首先下载avro-tools-1.9.1.jar文件将该文件连同dept.avsc放到同一个目录下,然后执行下面命令:
java -jar avro-tools-1.9.1.jar compile schema dept.avsc java.

注意:最后面的**java.**指的是生成的avro文件存放在当前目录下的java文件夹下,点表示当前路径。
最终在当前目录生成java/com/hc/bean目录下有个Dept.java文件。将该java文件和avsc文件一起拷贝到Intellij项目目录下面:

注:在Intellij中,也可以采用图形化的方式生成Java代码:

当然,也可以采用命令行的方式:
mvn clean install -DskipTests=true

不过使用mvn clean install -DskipTests=true命令时,需要添加下面Jackson注解,否则程序报错。

<dependency><groupId>com.fasterxml.jackson.core</groupId><artifactId>jackson-core</artifactId><version>2.10.1</version>
</dependency>
<dependency><groupId>com.fasterxml.jackson.core</groupId><artifactId>jackson-databind</artifactId><version>2.10.1</version>
</dependency>
<dependency><groupId>com.fasterxml.jackson.core</groupId><artifactId>jackson-annotations</artifactId><version>2.10.1</version>
</dependency>

第二步:使用Avro生成的代码创建Dept对象:

可以使用有参的构造函数和无参的构造函数,也可以使用Builder构造Dept对象:

@Test
public void genBean(){Dept dept1 = new Dept();dept1.setDeptno(50);dept1.setDname("aa");dept1.setLoc("aaaaaaaaaa");System.out.println(dept1);Dept dept2 = new Dept(60, "bb", "bbbbbbbbb");System.out.println(dept2);Dept dept3 = Dept.newBuilder().setDeptno(70).setDname("cc").setLoc("ccccccccc").build();System.out.println(dept3);
}

结果:

第三步:序列化:

@Test
public void serialize() throws IOException {Dept dept = new Dept(60, "bb", "bbbbbbbbb");DatumWriter<Dept> datumWriter = new SpecificDatumWriter<>(Dept.class); //缓存DataFileWriter<Dept> dataFileWriter = new DataFileWriter< >(datumWriter);dataFileWriter.create(dept.getSchema(), new File("dept.avro")); //将数据序列化到指定的文件中dataFileWriter.append(dept); //可以追加多个对象dataFileWriter.close();
}

上面代码中:DatumWrite接口用来把java对象转换成内存中的序列化格式,SpecificDatumWriter用来生成类并且指定生成的类型。最后使用DataFileWriter来进行具体的序列化,create方法指定目标文件和schema信息,append方法用来写数据,最后写完后close文件。
运行程序,结果:在当前目录生成一个名为dept.avro的二进制文件。

第四步:反序列化:

反序列化跟序列化很像,相应的Writer换成Reader。

@Test
public void deSerialize() throws IOException {File file = new File("dept.avro");DatumReader<Dept> datumReader = new SpecificDatumReader< >(Dept.class);DataFileReader<Dept> dataFileReader = new DataFileReader< >(file, datumReader);for(Dept dept : dataFileReader){ //通过迭代的方式一条条读取出来System.out.println(dept);}
}

上面代码只创建一个Dept对象,是为了性能优化,每次都重用这个Dept对象,如果文件量很大,对象分配和垃圾收集处理的代价很昂贵。最后使用 for (Dept dept: dataFileReader) 循环遍历对象

程序运行结果:

不使用生成的代码(类)进行序列化和反序列化(通用方式)

虽然Avro为我们提供了根据schema自动生成类的方法,我们也可以自己创建类,不使用Avro的自动生成工具。

第一步:创建Dept对象:

@Test
public void fun4() throws IOException {Schema schema = new Schema.Parser().parse(new File("src/main/resources/dept.avsc"));//通过流的方式将Schema信息构建出来GenericData.Record dept = new GenericData.Record(schema);dept.put("deptno","80");dept.put("dname","dd");dept.put("loc","ddddddddddd");System.out.println(dept);
}

上面代码首先使用Parser读取schema信息并且创建Schema类,有了Schema之后可以创建具体的Dept对象了。上面代码使用GenericRecord表示Dept,GenericRecord会根据schema验证字段是否正确,如果put进了不存在的字段 dept.put(“deptno”, “80”) ,那么运行的时候会得到AvroRuntimeException异常。
上面代码构建Schema也可以:

InputStream is = Thread.currentThread().getContextClassLoader().getResourceAsSteam("dept.avsc");
Schema schema = new Schema.Parser().parse(is);

第二步:通用序列化:

@Test
public void serialize() throws IOException {Schema schema = new Schema.Parser().parse(new File("src/main/resources/dept.avsc"));GenericRecord dept = new GenericData.Record(schema);dept.put("deptno", 90);dept.put("dname", "ee");dept.put("loc", "eeeeeeeee");DatumWriter<GenericRecord> datumWriter = new SpecificDatumWriter<>(schema); //泛型参数为GenericRecordDataFileWriter<GenericRecord> dataFileWriter = new DataFileWriter<>(datumWriter);dataFileWriter.create(schema, new File("dept.avro"));dataFileWriter.append(dept);dataFileWriter.close();
}

第三步:通用反序列化:

@Test
public void deSerialize() throws IOException {Schema schema = new Schema.Parser().parse(new File("src/main/resources/dept.avsc"));File file = new File("dept.avro");DatumReader<GenericRecord> datumReader = new SpecificDatumReader<GenericRecord>(schema);DataFileReader<GenericRecord> dataFileReader = new DataFileReader<GenericRecord>(file, datumReader);GenericRecord dept = null;while(dataFileReader.hasNext()) {dept = dataFileReader.next(dept );System.out.println(dept );}
}

执行程序,结果:

示例:基于通用序列化反序列化演示模式转换(数据投影):

原理:序列化的模式文件和反序列化的模式文件不一致。

情况一:模式文件字段重命名

  • 新创建模式文件dept2.avsc
{"namespace":"com.hc.bean",
"type":"record",
"name":"Dept",
"fields":[{"name":"deptno","type":"int"},{"name":"deptname","type":"string","aliases":["dname"]},{"name":"loc","type":"string"}
]
}

-测试代码:

@Test
public void fun41() throws IOException {//模式文件增加字段Schema schema = new Schema.Parser().parse(new File("src/main/resources/dept1.avsc"));File file = new File("src/main/resources/dept.avro");DatumReader<GenericRecord> datumReader = new SpecificDatumReader<>(schema);DataFileReader<GenericRecord> dataFileReader = new DataFileReader<>(file, datumReader);GenericRecord dept = null;while (dataFileReader.hasNext()) {dept = dataFileReader.next(dept);System.out.println(dept);}
}
  • 结果:

情况二:模式文件增加新的字段

  • 新创建模式文件dept2.avsc
{"namespace":"com.hc.bean",
"type":"record",
"name":"Dept",
"fields":[{"name":"deptno","type":"int"},{"name":"dname","type":"string"},{"name":"loc","type":"string"},{"name":"tel","type":"string","default":"110120"}
]
}
  • 测试代码:
@Test
public void fun42() throws IOException {//模式文件增加字段Schema schema = new Schema.Parser().parse(new File("src/main/resources/dept2.avsc"));File file = new File("src/main/resources/dept.avro");DatumReader<GenericRecord> datumReader = new SpecificDatumReader<>(schema);DataFileReader<GenericRecord> dataFileReader = new DataFileReader<>(file, datumReader);GenericRecord dept = null;while (dataFileReader.hasNext()) {dept = dataFileReader.next(dept);System.out.println(dept);}
}
  • 结果:

情况三:模式文件减少新的字段

  • 新创建模式文件dept3.avsc
{"namespace":"com.hc.bean",
"type":"record",
"name":"Dept",
"fields":[{"name":"deptno","type":"int"},{"name":"dname","type":"string"}
]
}
  • 测试代码:
@Test
public void fun43() throws IOException {//模式文件增加字段Schema schema = new Schema.Parser().parse(new File("src/main/resources/dept3.avsc"));File file = new File("src/main/resources/dept.avro");DatumReader<GenericRecord> datumReader = new SpecificDatumReader<>(schema);DataFileReader<GenericRecord> dataFileReader = new DataFileReader<>(file, datumReader);GenericRecord dept = null;while (dataFileReader.hasNext()) {dept = dataFileReader.next(dept);System.out.println(dept);}
}
  • 结果:

可以发现,上面几种情况,测试代码不用发生任何改变。这也正是采用通用模式的最大好处。


附:使用命令行的方式序列化/反序列化

第一步:提供表示数据的json文件:

{"deptno":10,"dname":"RESEARCH","loc":"DALLAS"}
{"deptno":20,"dname":"SALES","loc":"CHICAGO"}
{"deptno":30,"dname":"OPERATION","loc":"BOSTON"}
{"deptno":40,"dname":"ACCOUNTING","loc":"NEW YORK"}

第二步:使用avro工具将json文件转换成avro文件:

命令:java -jar avro-tools-1.9.1.jar fromjson --schema-file dept.avsc dept.json > dept.avro

可以设置压缩格式,命令:
java -jar avro-tools-1.9.1.jar fromjson --codec snappy --schema-file dept.avsc dept.json > dept2.avro

第三步:将avro文件反转换成json文件:

命令:java -jar avro-tools-1.9.1.jar tojson dept.avro

第四步:得到avro文件的meta:

命令:java -jar avro-tools-1.9.1.jar getmeta dept.avro

avro数据序列化/反序列化相关推荐

  1. Avro 数据序列化

    Apache Avro 是一个独立于编程语言的数据序列化系统.旨在解决Hadoop中Writable类型的不足:缺乏语言的可移植性.Avro 模式通常用json来写,数据通常采用二进制格式编码. Av ...

  2. hadoop的Avro数据序列化系统

    1.什么是Avro Avro设计用于支持大批量数据交换的应用 Avro可以将数据结构或者对象转换成便于存储或者传输的格式. 为了hadoop的前途考虑,DougCutting主导开发的一套新的序列化系 ...

  3. 一文解析Apache Avro数据

    摘要:本文将演示如果序列化生成avro数据,并使用FlinkSQL进行解析. 本文分享自华为云社区<[技术分享]Apache Avro数据的序列化.反序列&&FlinkSQL解析 ...

  4. java读avro的流_0016-Avro序列化反序列化和Spark读取Avro数据

    1.简介 本篇文章主要讲如何使用java生成Avro格式数据以及如何通过spark将Avro数据文件转换成DataSet和DataFrame进行操作. 1.1Apache Arvo是什么? Apach ...

  5. 0016-Avro序列化反序列化和Spark读取Avro数据

    温馨提示:要看高清无码套图,请使用手机打开并单击图片放大查看. 1.简介 本篇文章主要讲如何使用java生成Avro格式数据以及如何通过spark将Avro数据文件转换成DataSet和DataFra ...

  6. kafka python框架_Python中如何使用Apache Avro——Apache的数据序列化系统

    了解如何创建和使用基于Apache Avro的数据,以实现更好,更有效的传输. 在这篇文章中,我将讨论Apache Avro,这是一种开源数据序列化系统,Spark,Kafka等工具正在使用该工具进行 ...

  7. php serialize unserialize 数据序列化 与 反序列化

    序列化就是将一个对象的状态(各个属性量)保存起来,然后在适当的时候再获得. 用一个类的时候都是new一下! 如果serialize 将数据序列化以后存到数据库中等  用的时候就不再new了 反序列化以 ...

  8. 序列化--反序列化:Schema evolution in Avro, Protocol Buffers and Thrift

    当想要数据, 比如对象或其他类型的, 存到文件或是通过网络传输, 需要面对的问题是序列化问题 对于序列化, 当然各个语言都提供相应的包, 比如, Java serialization, Ruby's ...

  9. Java实现数据序列化工具Avro的例子

    1.Avro简介 Avro是一个数据序列化的系统. 它可以提供: 1)丰富的数据结构类型 2)快速可压缩的二进制数据形式 3)存储持久数据的文件容器 4)远程过程调用RPC 5)简单的动态语言结合功能 ...

最新文章

  1. python语言入门m-Python2 教程
  2. (数据挖掘 —— 无监督学习(聚类)
  3. c语言创建文件的作用,c语言文件创建与建立
  4. 用python编辑word_使用PYTHON编辑和读取WORD文档
  5. php 设置post大小_post 数据大小的限制问题
  6. mysql5.7.28升级到5.7.29_MySQL升级5.7.29
  7. mysql中 s命令_MySQL的基本操作命令
  8. Apache Kafka简介与安装(一)
  9. 截图上传录屏gif上传工具推荐
  10. php编网页版计算器,php编程实现简单的网页版计算器功能
  11. 小谈 《日内交易策略--谷物期货交易实战指南》中提到的策略
  12. 使用屏幕录制专家--录制视频技巧
  13. 【转载】数学专业的数学与计算机专业的数学的比较
  14. PLC程序案例一:喷泉电路(采用中间继电器完成分步控制)
  15. 25.mc_api介绍及使用示例
  16. 程序员如何培养第二技能?
  17. request Headers字段详解
  18. 雪亮工程建设标准_为什么建设雪亮工程以及建设雪亮工程的几个要点
  19. mock.js 使用说明( 简单而有效 )
  20. 西门子300PLC的定时器用法

热门文章

  1. UDS protocol - 周期报文 periodical message 多字节通信 multi-byte message
  2. 【内网学习笔记】9、iodine 使用
  3. QT软件开发: QPlainTextEdit当做日志显示窗口
  4. 至少值一个淘宝的自由服务市场
  5. 【利用python进行数据分析】之安装EPD
  6. 通过RGB LED模块设计带有测量值显示的色彩传感器
  7. 螺线管、螺线管线圈磁场、空心线圈磁场
  8. [Windows] Adobe Photoshop 2021 22.0.02021
  9. 奥鹏教育多媒体计算机技术19秋在线作业2,[东北师范大学]《多媒体计算机技术》19秋在线作业21(100分)...
  10. 信息安全密码学:RSA密码体制