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

时间:2022-04-11 07:06:21

                   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进行序列化和反序列化的代码如下

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

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

 /*
@author :yinzhengjie
Blog:http://www.cnblogs.com/yinzhengjie/tag/Hadoop%E8%BF%9B%E9%98%B6%E4%B9%8B%E8%B7%AF/
EMAIL:y1053419035@qq.com
*/
package cn.org.yinzhengjie.serialize; import org.apache.hadoop.io.IntWritable;
import java.io.*; public class HadoopSerial {
public final static String fileParh = "D:\\10.Java\\IDE\\yhinzhengjieData\\Datahadoop.serial";
public static void main(String[] args) throws IOException {
intSerialze();
intDeserialize();
} //定义序列化方式
public static void intSerialze() throws IOException {
//初始化intWritable
IntWritable iw = new IntWritable(2018);
FileOutputStream fos = new FileOutputStream(fileParh);
DataOutputStream dos = new DataOutputStream(fos);
//进行Hadoop的序列化方式
iw.write(dos);
//别忘记释放资源哟
dos.close();
fos.close();
} //定义反序列化方式
public static void intDeserialize() throws IOException {
//初始化intWritable
IntWritable iw = new IntWritable();
FileInputStream fis = new FileInputStream(fileParh);
DataInputStream dis = new DataInputStream(fis);
//进行Hadoop的反序列化方式,将数据输入流的数据传递给iw对象的readFields方法。
iw.readFields(dis);
//再通过iw对象的get方法获取数据
int res = iw.get();
System.out.println(res);
}
} /*
以上代码执行结果如下:
2018
*/

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

  Datahadoop.serial 文件属性如下:

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

  java.serial 文件属性如下:

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

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

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

 /*
@author :yinzhengjie
Blog:http://www.cnblogs.com/yinzhengjie/tag/Hadoop%E8%BF%9B%E9%98%B6%E4%B9%8B%E8%B7%AF/
EMAIL:y1053419035@qq.com
*/ package cn.org.yinzhengjie.serialize; import java.io.Serializable; public class Student implements Serializable {
private String name;
private int age;
private boolean ismarry; public String getName() {
return name;
} public int getAge() {
return age;
} public boolean isIsmarry() {
return ismarry;
} public void setName(String name) {
this.name = name;
} public void setAge(int age) {
this.age = age;
} public void setIsmarry(boolean ismarry) {
this.ismarry = ismarry;
} @Override
public String toString() {
return "Student{" +
"name='" + name + '\'' +
", age=" + age +
", ismarry=" + ismarry +
'}';
}
}

Student.java 文件内容

1>.java对自定义Student类实现序列化和反序列化

 /*
@author :yinzhengjie
Blog:http://www.cnblogs.com/yinzhengjie/tag/Hadoop%E8%BF%9B%E9%98%B6%E4%B9%8B%E8%B7%AF/
EMAIL:y1053419035@qq.com
*/
package cn.org.yinzhengjie.serialize; import java.io.*; public class JavaSerial {
public final static String fileParh = "D:\\10.Java\\IDE\\yhinzhengjieData\\java.student";
public static void main(String[] args) throws Exception {
studentSerialze();
studentDeserialize();
}
//定义序列化方式
public static void studentSerialze() throws IOException {
//实例化对象yzj
Student yzj = new Student();
yzj.setName("尹正杰");
yzj.setAge(18);
yzj.setIsmarry(false);
FileOutputStream fos = new FileOutputStream(fileParh);
ObjectOutputStream oos = new ObjectOutputStream(fos);
//进行Java的序列化方式
oos.writeObject(yzj);
//释放资源
oos.close();
fos.close(); //这里其实可以不用写,因为上面一行释放资源会顺带把它封装的对线下也关流了,不过这行即使咱们写了也是不会报错的!
}
//定义反序列化方法
public static void studentDeserialize() throws Exception {
FileInputStream fis = new FileInputStream(fileParh);
ObjectInputStream ois = new ObjectInputStream(fis);
//调用反序列化流的方法"readObject()"读取对象,要注意的是反序列话的对象需要存在相应的字节码文件。否则会抛异常
Object res = ois.readObject();
//释放资源
ois.close();
fis.close();
System.out.println(res);
}
} /*
以上代码执行结果如下:
Student{name='尹正杰', age=18, ismarry=false}
*/

2>.Hadoop对自定义Student类实现序列化和反序列化

  Hadoop对自定义类实现序列化或者反序列化操作的话,需要实现Hadoop的Writable接口,接下来我们举个例子,代码如下:

 /*
@author :yinzhengjie
Blog:http://www.cnblogs.com/yinzhengjie/tag/Hadoop%E8%BF%9B%E9%98%B6%E4%B9%8B%E8%B7%AF/
EMAIL:y1053419035@qq.com
*/ package cn.org.yinzhengjie.serialize; import org.apache.hadoop.io.Writable; import java.io.DataInput;
import java.io.DataOutput;
import java.io.IOException; public class StudentWirtable implements Writable { //切记这里需要给student赋值,不然可能会报错空指针异常哟!
private Student student = new Student(); public Student getStudent() {
return student;
} public void setStudent(Student student) {
this.student = student;
} //定义串行化的方法
public void write(DataOutput dataOutput) throws IOException {
//定义自定义类的序列化顺序,我这里是先序列化name,在序列化age,最好才序列化ismarry。
dataOutput.writeUTF(student.getName());
dataOutput.writeInt(student.getAge());
dataOutput.writeBoolean(student.isIsmarry()); } //定义反串行化的方法
public void readFields(DataInput dataInput) throws IOException {
student.setName(dataInput.readUTF());
student.setAge(dataInput.readInt());
student.setIsmarry(dataInput.readBoolean());
}
}

  接下来就是我们调用自己定义的序列化方法啦,测试代码如下:

 /*
@author :yinzhengjie
Blog:http://www.cnblogs.com/yinzhengjie/tag/Hadoop%E8%BF%9B%E9%98%B6%E4%B9%8B%E8%B7%AF/
EMAIL:y1053419035@qq.com
*/
package cn.org.yinzhengjie.serialize; import java.io.*; public class HadoopSerial {
public final static String fileParh = "D:\\10.Java\\IDE\\yhinzhengjieData\\hadoop.student";
public static void main(String[] args) throws IOException {
studentSerialze();
studentDeserialize();
} //定义序列化方式
public static void studentSerialze() throws IOException {
//实例化对象yzj
Student yzj = new Student();
yzj.setName("尹正杰");
yzj.setAge(18);
yzj.setIsmarry(false);
//初始化StudentWirtable,这是咱们定义的一个容器
StudentWirtable sw = new StudentWirtable();
sw.setStudent(yzj);
FileOutputStream fos = new FileOutputStream(fileParh);
DataOutputStream dos = new DataOutputStream(fos);
//进行Hadoop的序列化方式
sw.write(dos);
//别忘记释放资源哟
dos.close();
fos.close();
} //定义反序列化方式
public static void studentDeserialize() throws IOException {
//初始化intWritable
StudentWirtable sw = new StudentWirtable();
DataInputStream dis = new DataInputStream(new FileInputStream(fileParh));
sw.readFields(dis);
Student yzj = sw.getStudent();
dis.close();
System.out.println(yzj.toString()); }
} /*
以上代码执行结果如下:
Student{name='尹正杰', age=18, ismarry=false}
*/

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

   hadoop.student 文件属性如下:

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

  java.student 文件属性如下:

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

  如果一个int类型你感觉不出来hadoop序列化和java序列化的区别,那么自定义类的属性进行序列化你应该明显的看出来hadoop序列化要比java传统的序列化方式要节省空间多的多,如果这个数据换成一个PB的大小的话,估计差距就是天壤之别啦!

 

 

Hadoop基础-序列化与反序列化(实现Writable接口)的更多相关文章

  1. eclipse 提交作业到JobTracker Hadoop的数据类型要求必须实现Writable接口

    问:在eclipse中的写的代码如何提交作业到JobTracker中的哪?答:(1)在eclipse中调用的job.waitForCompletion(true)实际上执行如下方法 connect() ...

  2. Java基础—序列化与反序列化(转载)

    转载自: Java序列化与反序列化 1.Java序列化与反序列化 Java序列化是指把Java对象转换为字节序列的过程:而Java反序列化是指把字节序列恢复为Java对象的过程. 2.为什么需要序列化 ...

  3. Hadoop序列化与Writable接口(一)

    Hadoop序列化与Writable接口(一) 序列化 序列化(serialization)是指将结构化的对象转化为字节流,以便在网络上传输或者写入到硬盘进行永久存储:相对的反序列化(deserial ...

  4. 使用Json.Net处理json序列化和反序列化接口或继承类

    以前一直没有怎么关注过Newtonsoft的Json.Net这个第三方的.NET Json框架,主要是我以前在开发项目的时候大多数使用的都是.NET自带的Json序列化类JavaScriptSeria ...

  5. C#实现接口xml序列化与反序列化

    C#实现接口xml序列化与反序列化   C#中接口无法被xml序列化,提示不支持.百度和bing也搜不到,只好自己动手写了 原理上肯定支持,.Net自己的xml序列化有一个IXmlSerializab ...

  6. 初识序列化和反序列化,使用BinaryFormatter类、ISerializable接口、XmlSerializer类进行序列化和反序列化

    序列化是将对象转换成字节流的过程,反序列化是把字节流转换成对象的过程.对象一旦被序列化,就可以把对象状态保存到硬盘的某个位置,甚至还可以通过网络发送给另外一台机器上运行的进程.本篇主要包括: ● 使用 ...

  7. Hadoop 的序列化

    1. 序列化 1.1 序列化与反序列化的概念 序列化:是指将结构化对象转化成字节流在网上传输或写到磁盘进行永久存储的过程 反序列化:是指将字节流转回结构化对象的逆过程 1.2 序列化的应用 序列化用于 ...

  8. java中对象的序列化和反序列化

    [对象的序列化和反序列化 ] 1.定义:序列化--将对象写到一个输出流中.反序列化则是从一个输入流中读取一个对象.类中的成员必须是可序列化的,而且要实现Serializable接口,这样的类的对象才能 ...

  9. Jedis和JAVA对象的序列化和反序列化的使用

    1. Jedis版本: jedis-2.6.2.jar 背景:现在系统提供portal接口服务,使用JDBC直接查询数据库,使用jedis提供的缓存功能,在JDBC前面加上Redis,先从Redis中 ...

随机推荐

  1. ThinkPHP3.1.3源码分析---php文件压缩zlib.output_compression 和 ob_gzhandler

    问题来源:\ThinkPHP3.1.3_full\ThinkPHP\Lib\Core\App.class.php 中 init()方法      if(C('OUTPUT_ENCODE')){     ...

  2. 【Linux】系统 之 RAID

    本人从事DBA相关的工作,最近遇到了IO抖动伴随shread running抖动的情况,主机宕机重启后备库及下游解析binlog出现损坏的案例,向一些有经验的同事咨询学习,其中最大的嫌疑是:raid卡 ...

  3. bzoj1064

    很巧妙的题 首先有几种情况 1. 有环 2.两点间有多条路径 3.其他 3.显然最简单,最小是3,最大是每个弱联通块中最长链 2.显然,两点间两条路径的差是答案的倍数 1.出现环,那答案一定是其约数, ...

  4. github 查看单个文件的历史记录命令

    gitk 安装: apt-get install gitk 点击打开链接http://*.com/questions/278192/view-the-change-histor ...

  5. leetcode 326. Power of Three(不用循环或递归)

    leetcode 326. Power of Three(不用循环或递归) Given an integer, write a function to determine if it is a pow ...

  6. 原生封装ajax

    01.声明一个全局变量 02.开始封装,判断参数 03.属性的var自定义 04.请求 01.请求行 02.请求头 03.请求发送 05.响应 01.事件监听onreadystatechange 02 ...

  7. linux中centros6.7安装php5.6,httpd-2.2.19(web产品化)遇到的问题总结

    前段时间在公司实习,web系统产品化的过程踩了很多坑,在这边总结一下,由于对linux不是很懂,全是自己一步步一个一个问题解决的 1,查看系统中是否安装apache,php,mysql环境 Apach ...

  8. python中的keys、values、items

    keys()获取字典中所有的键并放入列表 values()获取字典中所有的值并放入列表 items()获取字典中所有的键值对并放入列表 举个例子: 1 a = { 2 "name" ...

  9. 关于AVAYA CM6和Asterisk(Freepbx)对接的笔记

    最重要的两份参考文档: http://blog.sina.com.cn/s/blog_6db134880102vipo.html https://personalprojects.wordpress. ...

  10. 关于ArcGIS Server修改数据源是否对切片服务有影响

    感谢一路走来默默支持和陪伴的你~~~ ------------------欢迎来访,拒绝转载------------------- (一)问题: 一直有人问一个问题: 1.我发布了切片的地图服务一以后 ...

相关文章