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 文件属性如下:

  java.serial 文件属性如下:

  同样都是对一个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 文件属性如下:

  java.student 文件属性如下:

  如果一个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. Java基础--序列化和反序列化

    作用:在很多应用中,需要对某些对象进行序列化,让它们离开内存空间,入住物理硬盘,以便长期保存.比如最常见的是Web服务器中的Session对象,当有 10万用户并发访问,就有可能出现10万个Sessi ...

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

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

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

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

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

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

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

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

  8. Hadoop 的序列化

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

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

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

随机推荐

  1. Daily Scrum7 11.11

    今日任务: 徐钧鸿:结束了SQL和Affairs的移植,修改了连接池,学习C#和java的正则表达式并且完成相关的移植 张艺:个人阅读作业 黄可嵩:完成高亮显示的移植,进一步移植搜索代码 徐方宇:继续 ...

  2. 【Alpha】Task分配与计划发布

     团队项目链接 以上大概是我们的任务分配,根据目前的预计时间来看,到α版本项目稳定下来至少需要440小时的开发时间才能完成. 项目最大的问题点和难点在于其数据量非常之大,计算模块要求非常之多,想象一下 ...

  3. OO学习总结与体会

    前言 经过了对于面向对象程序设计的一个月的学习,我初尝了JAVA以及面向对象程序的魅力.经历了三次难度逐渐加大的课后编程作业,我对于工程化面向对象编程以及调试有了深刻的认识与颇多感想.我写下本篇文章以 ...

  4. 2018-2019-20172329 《Java软件结构与数据结构》第八周学习总结

    2018-2019-20172329 <Java软件结构与数据结构>第八周学习总结 现在对于我而言,最珍贵的是时间,感觉自己在时间飞逝的时候真的挽留不住什么,只能怒发冲冠的让自己疯狂的学习 ...

  5. Sprint7

    进展:根据昨天查到的资料,今天开始编写闹钟部分的代码,主要实现了闹钟添加事件显示时间主界面.

  6. Leetcode题库——14.最长公共前缀

    @author: ZZQ @software: PyCharm @file: longestCommonPrefix.py @time: 2018/9/16 17:50 要求:查找字符串数组中的最长公 ...

  7. Week2:阅读笔记与思考

    <构建之法>这本书的内容通俗易懂,每一个知识点都有许多事例佐证,阅读起来不像其他教科书那样枯燥无聊.但阅读过第一.二.十六章之后还是产生了几个疑问,以及更深层次的思考. 第一章 问题1: ...

  8. 循环队列的C语言实现

    生活中有很多队列的影子,比如打饭排队,买火车票排队问题等,可以说与时间相关的问题,一般都会涉及到队列问题:从生活中,可以抽象出队列的概念,队列就是一个能够实现“先进先出”的存储结构.队列分为链式队列和 ...

  9. form表单转化json对象

    利用 $.fn 可以让每一个jquery 对象都能直接使用这个方法. //form表单转化json对象$.fn.serializeObject = function () { var o = {}; ...

  10. debug阶段贡献分

    组名: 新蜂 组长: 武志远 组员: 宫成荣 谢孝淼 杨柳 李峤 项目名称: java俄罗斯方块NEO 发布时间:11.29 武志远 武志远 武志远 武志远 武志远 宫成荣 宫成荣 杨柳 宫成荣 宫成 ...