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. iOS开发学习-给圆形图片添加边框

    imageView.layer.cornerRadius = imageView.bounds.size.width * 0.5;// 设置圆角刚好是自身宽度的一半,就刚好是圆形 imageView. ...

  2. SQL之联合查询学习笔记

    定义: 联合查询可合并多个相似的选择查询的结果集.等同于将一个表追加到另一个表,从而实现将两个表的查询组合到一起,使用谓词为UNION或UNION ALL. 语法格式 UNION 可以将两个或两个以上 ...

  3. php 把数字转化为大写中文

    PHP 数字转大写中文 PHP入门小菜鸟一枚.下午要求写一个把数字转成大写中文的脚本,百度了一波,几十个博客和网站都是用的那四个代码,第一个运行不了,第二个有问题,不合要求,第三个第四个太长,懒得看, ...

  4. Java中DAO的实现

    J2EE 开发人员使用数据访问对象(Data Access Object DAO)设计模式,以便将低级别的数据访问逻辑与高级别的业务逻辑分离.实现 DAO 模式涉及比编写数据访问代码更多的内容.在本文 ...

  5. flex 布局能解决的问题

    flex 布局,可以解决元素在容器中的对齐.方向.顺序,甚至它们是动态的或者不确定大小的新布局模型.Flex容器的主要特征是能够调整其子元素在不同的屏幕大小中能够用最适合的方法填充合适的空间 . 转载 ...

  6. 个人作业-week3案例分析

    第一部分 软件调研测评(必应词典移动端) 找到的bug: 在词汇量测试中每个单词给用户思考的时间太短,只有五秒钟.导致很多似曾相识的单词还没来得及想起就已经过了.如果说测的是用户记忆深刻的单词,那些记 ...

  7. “Unable to open kernel device \\.\Global\vmx86

    启动vm中虚拟机中的时候,弹出窗口的时候,弹出窗口 Unable to open kernel device \\.\Global\vmx86;系统找不到指定的文件,Did you reboot af ...

  8. oracle greatest(),least( ) ,coalesce()

    --场景1: select pt, greatest(wm), least(wm) from (select s.producttype pt, wm_concat(s.productid) wm f ...

  9. xpath 去除空格

    normalize,字面意思就是正规化 加入space  大概意思就是空格的处理了 官方解释是这样的: 通过去掉前导和尾随空白并使用单个空格替换一系列空白字符,使空白标准化.如果省略了该参数,上下文节 ...

  10. Java继承,重写方法时改变方法的访问权限

    java中的方法天生具有继承多态特性,这点与C++有很大不同(需要在父类方发上加virtual关键字),但用起来确实方便了许多. 最简单的继承多态 声明一个接口BaseIF,只包含一个方法声明 pub ...