Hadoop基础-序列化与反序列化(实现Writable接口)

                                            作者:尹正杰

版权声明:原创作品,谢绝转载!否则将追究法律责任。

 

 

 

 

一.序列化简介

1>.什么是序列化

  序列化也称串行化,是将结构化的对象转换成字节流,以便在网络上进行传输或者写入到磁盘进行永久性存储的过程。

2>.什么是反序列化

  反序列化也称反串行化,它是指将字节流转回结构化对象的逆过程。

3>.序列化的应用

  主要用于分布式数据处理的两大领域,即进程间通信和永久存储。

4>.序列化的特点

  第一:紧凑,体积小,节省带宽;

  第二:快速,序列化过程快速;

  第三:可扩展性(向下兼容),新API支持旧数据格式;

  第四:支持互操作,跨语言(可惜的是Java序列化和hadoop序列化都没有实现该属性!);

   遗憾的是,Java和hadoop序列化都不支持上述的第四点特性,即跨语言。目前流行的两个序列化框架avro和protobuf(由Google公司研发)都支持以上四个特性哟!这两个框架不是本篇博客的重点,后期我会写两篇关于这两个序列化框架笔记。

 

二.hadoop串行化介绍

1>.为什么Hadoop要自己定义Hadoop串行化

  之前我分享过Java序列化的通过ObjectOutputStream流对象可以对任意实现Serializable类接口进行实例化操作的笔记。通过ObjectInputStream流对象可以进行反序列化操作,详情请参考:https://www.cnblogs.com/yinzhengjie/p/8988003.html

  遗憾的是Hadoop并没有使用ObjectOutputStream进行序列化操作,而是自己定义了序列化的格式。可能你会跟当初刚刚学习Hadoop的我问同样的问题:“为什么Hadoop不Java自己提供的实现Serializable接口的方式进行序列化操作呢?”,每一件事物的存在都有他的原因,Hadoop自己定义了序列话接口是Hadoop处理的数据是海量的,他们对数据的存储,以及压缩算法是有要求的,感兴趣的小伙伴可以对一个较大数据进行序列化操作,你会发现Hadoop的序列化方式的确挺牛的!

2>.hadoop串行化格式

  Hadoop把Java的几种数据类型进行了封装,将Long类型的数据封装为LongWritable,将int类型的数据进行封装为IntWritable类型,将String类型数据封装为Text类型,将Byte类型封装为ByteWriterable,将Array类型封装为ArrayWritale类型等等;

 

三.比较Java和Hadoop对int类型的串行化格式

1>.Java对int值2018进行序列化和反序列化的代码如下

 1 /*
 2 @author :yinzhengjie
 3 Blog:http://www.cnblogs.com/yinzhengjie/tag/Hadoop%E8%BF%9B%E9%98%B6%E4%B9%8B%E8%B7%AF/
 4 EMAIL:y1053419035@qq.com
 5 */
 6 package cn.org.yinzhengjie.serialize;
 7 
 8         import java.io.*;
 9 
10 public class JavaSerial {
11     public final static String fileParh = "D:\\10.Java\\IDE\\yhinzhengjieData\\java.serial";
12     public static void main(String[] args) throws Exception {
13         intSerialze();
14         intDeserialize();
15     }
16     //定义序列化方式
17     public static void intSerialze() throws IOException {
18         Integer i = 2018;
19         FileOutputStream fos = new FileOutputStream(fileParh);
20         ObjectOutputStream oos = new ObjectOutputStream(fos);
21         //进行Java的序列化方式
22         oos.writeInt(i);
23         //释放资源
24         oos.close();
25         fos.close();    //这里其实可以不用写,因为上面一行释放资源会顺带把它封装的对线下也关流了,不过这行即使咱们写了也是不会报错的!
26     }
27     //定义反序列化方法
28     public static void  intDeserialize() throws Exception {
29         FileInputStream fis = new FileInputStream(fileParh);
30         ObjectInputStream ois = new ObjectInputStream(fis);
31         //调用反序列化流的方法"readInt()"读取对象,要注意的是反序列话的对象需要存在相应的字节码文件。否则会抛异常
32         int res = ois.readInt();
33         //释放资源
34         ois.close();
35         fis.close();
36         System.out.println(res);
37     }
38 }
39 
40 
41 /*
42 以上代码执行结果如下:
43 2018
44 */

2>.Hadoop对int类型的序列化方式和反序列化的代码如下

 1 /*
 2 @author :yinzhengjie
 3 Blog:http://www.cnblogs.com/yinzhengjie/tag/Hadoop%E8%BF%9B%E9%98%B6%E4%B9%8B%E8%B7%AF/
 4 EMAIL:y1053419035@qq.com
 5 */
 6 package cn.org.yinzhengjie.serialize;
 7 
 8 import org.apache.hadoop.io.IntWritable;
 9 import java.io.*;
10 
11 public class HadoopSerial {
12     public final static String fileParh = "D:\\10.Java\\IDE\\yhinzhengjieData\\Datahadoop.serial";
13     public static void main(String[] args) throws IOException {
14         intSerialze();
15         intDeserialize();
16     }
17 
18     //定义序列化方式
19     public static void intSerialze() throws IOException {
20         //初始化intWritable
21         IntWritable iw = new IntWritable(2018);
22         FileOutputStream fos = new FileOutputStream(fileParh);
23         DataOutputStream dos = new DataOutputStream(fos);
24         //进行Hadoop的序列化方式
25         iw.write(dos);
26         //别忘记释放资源哟
27         dos.close();
28         fos.close();
29     }
30 
31     //定义反序列化方式
32     public static void  intDeserialize() throws IOException {
33         //初始化intWritable
34         IntWritable iw = new IntWritable();
35         FileInputStream fis = new FileInputStream(fileParh);
36         DataInputStream dis = new DataInputStream(fis);
37         //进行Hadoop的反序列化方式,将数据输入流的数据传递给iw对象的readFields方法。
38         iw.readFields(dis);
39         //再通过iw对象的get方法获取数据
40         int res = iw.get();
41         System.out.println(res);
42     }
43 }
44 
45 /*
46 以上代码执行结果如下:
47 2018
48 */

3>.查看两种方式的序列化文件大小

  Datahadoop.serial 文件属性如下:

Hadoop基础-序列化与反序列化(实现Writable接口)

  java.serial 文件属性如下:

Hadoop基础-序列化与反序列化(实现Writable接口)

  同样都是对一个int类型值为2018的数字进行序列化,为什么Hadoop序列化只需要4个字节,而Java却需要10个字节呢?如果数字是PB的数据量,在选择序列化的方案上你会选择哪个呢?

 

四.比较java与Hadoop对自定义类的串行化格式

 1 /*
 2 @author :yinzhengjie
 3 Blog:http://www.cnblogs.com/yinzhengjie/tag/Hadoop%E8%BF%9B%E9%98%B6%E4%B9%8B%E8%B7%AF/
 4 EMAIL:y1053419035@qq.com
 5 */
 6 
 7 package cn.org.yinzhengjie.serialize;
 8 
 9 import java.io.Serializable;
10 
11 public class Student implements Serializable {
12     private  String name;
13     private  int age;
14     private  boolean ismarry;
15 
16     public String getName() {
17         return name;
18     }
19 
20     public int getAge() {
21         return age;
22     }
23 
24     public boolean isIsmarry() {
25         return ismarry;
26     }
27 
28     public void setName(String name) {
29         this.name = name;
30     }
31 
32     public void setAge(int age) {
33         this.age = age;
34     }
35 
36     public void setIsmarry(boolean ismarry) {
37         this.ismarry = ismarry;
38     }
39 
40     @Override
41     public String toString() {
42         return "Student{" +
43                 "name='" + name + '\'' +
44                 ", age=" + age +
45                 ", ismarry=" + ismarry +
46                 '}';
47     }
48 }
Student.java 文件内容

相关文章: