序列化从头说
在面向对象程序设计中,类是个很重要的概念。所谓“类”,可以将它想像成建筑图纸,而对象就是根据图纸盖的大楼。类,规定了对象的一切。根据建筑图纸造房子,盖出来的就是大楼,等同于将类进行实例化,得到的就是对象。
一开始,在源代码里,类的定义是明确的,但对象的行为有些地方是明确的,有些地方是不明确的。对象里不明确地方,是因为对象在运行的时候,需要处理无法预测的事情,诸如用户点了下屏幕,用户点了下按钮,输入点东西,或者需要从网络发送接收数据之类的。后来,引入了泛型的概念之后,类也开始不明确了,如果使用了泛型,直到程序运行的时候,才知道究竟是哪种对象需要处理。
对象可以很复杂,也可以跟时序相关。一般来说,“活的”对象只生存在内存里,关机断电就没有了。一般来说,“活的”对象只能由本地的进程使用,不能被发送到网络上的另外一台计算机。
序列化,可以存储“活的”对象,可以将“活的”对象发送到远程计算机。
把“活的”对象序列化,就是把“活的”对象转化成一串字节,而“反序列化”,就是从一串字节里解析出“活的”对象。于是,如果想把“活的”对象存储到文件,存储这串字节即可,如果想把“活的”对象发送到远程主机,发送这串字节即可,需要对象的时候,做一下反序列化,就能将对象“复活”了。
将对象序列化存储到文件,术语又叫“持久化”。将对象序列化发送到远程计算机,术语又叫“数据通信”。
Java对序列化提供了非常方便的支持,在定义类的时候,如果想让对象可以被序列化,只要在类的定义上加上了”implements Serializable”即可,比如说,可以这么定义”public class Building implements Serializable”,其他什么都不要做,Java会自动的处理相关一切。Java的序列化机制相当复杂,能处理各种对象关系。
Java的序列化机制的缺点就是计算量开销大,且序列化的结果体积大太,有时能达到对象大小的数倍乃至十倍。它的引用机制也会导致大文件不能分割的问题。这些缺点使得Java的序列化机制对Hadoop来说是不合适的。于是Hadoop设计了自己的序列化机制。
为什么序列化对Hadoop很重要?因为Hadoop在集群之间进行通讯或者RPC调用的时候,需要序列化,而且要求序列化要快,且体积要小,占用带宽要小。所以必须理解Hadoop的序列化机制。
2. Hadoop的序列化接口
什么是接口?简答来说,接口就是规定,它规定类必须实现的方法。一个接口可以包含多干个方法。如果一个类说自己实现了某个接口,那么它必须实现这个接口里的所有方法。特殊情况下,接口也可以没有任何方法。
Writable接口,也就是org.apache.hadoop.io.Writable接口。Hadoop的所有可序列化对象都必须实现这个接口。Writable接口里有两个方法,一个是write方法,将对象写入字节流,另一个是readFields方法,从字节流解析出对象。
Java的API提供了Comparable接口,也就是java.lang.Comparable接口。这个接口只有一个方法,就是compareTo,用于比较两个对象。
WritableComparable接口同时继承了Writable和Comparable这两个接口。
Hadoop里的三个类IntWritable、DoubleWritable和ByteWritable,都继承了WritableComparable接口。注意,IntWritable、DoubleWritable和ByteWritable,尽管后缀是“Writable”,但它们不是接口,是类!!
以上是摘自大神博文。
下面是自己总结代码
代码:package xlh;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import org.apache.hadoop.io.IntWritable;
import org.apache.hadoop.util.StringUtils;
public class inser {
/**
* 序列化步骤
* 1.声明一个静态的类型时数组的函数,并在里面传递参数,而这个参数是Hadoop 里面InWritable 类的对象
* 2.使用Java.io包下的ByteArrayOutputStream 这个类并实例化,取名为out 即输出对象,这里是从本地文件输入到hdfs 上 还起到把结构化数据转化为字符流
* 3.使用Java.io包下的DataOutputStream 类并实例化,取名为dataoutput ,这里参数是out
* 4.调用InWritable 类的对像的write(); 顾名思义,要把本地文件写到hdfs上
* 5.关闭数据流对象
* 6.返回值,返回out对象的toByteArray(); 这个含义,我也不是太清楚
*/
public static byte[] serialize(IntWritable intw) throws IOException {
ByteArrayOutputStream out = new ByteArrayOutputStream();
DataOutputStream dataoutput = new DataOutputStream(out);
intw.write(dataoutput);
dataoutput.close();
return out.toByteArray();
}
/**
* 反序列化步骤
* 1.声明一个静态的类型时数组的函数,并在里面传递参数,而这个参数是Hadoop 里面InWritable 类的对象
* 2.使用Java.io包下的ByteArrayOutputStream 这个类并实例化,取名为in,即输入对象,这里是从hdfs 上文件输入到 本地,还起到把结构化数据转化为字符流
* 3.使用Java.io包下的DataIutputStream 类并实例化,取名为datain ,这里参数是in
* 4.调用InWritable 类的对像的readFields(); 顾名思义,要把hdfs上文件写到本地
* 5.关闭数据流对象
* 6.返回值
*/
public static byte[] deserialize(IntWritable intw2, byte[] bytes) throws IOException {
ByteArrayInputStream in = new ByteArrayInputStream(bytes);
DataInputStream datain = new DataInputStream(in);
intw2.readFields(datain);
datain.close();
return bytes;
}
/* 使用Hadoop中的intwritable 类并实例化
* 声明数组,并把inwritable 类对象intw 当做参数传给serialize
* 开始执行序列化
*
*
*
* 使用Hadoop中的intwritable 类并实例化
* 声明数组,并把inwritable 类对象intw 当做参数传给serialize
* 开始执行反序列化
*
*
* */
public static void main(String[] args) throws IOException {
IntWritable intw = new IntWritable();
byte[] bytes = serialize(intw);
String bytes_str = StringUtils.byteToHexString(bytes);
System.out.println(bytes_str);
IntWritable intw2 = new IntWritable(0);
deserialize(intw2, bytes);
System.out.println(intw2);
}
}
个人小体会:
今天敲这写代码给我的感觉,在此之前,我也看了关于序列化相关知识,但都是一脸懵逼的看,一脸懵逼的不懂!就是之前学习完全没用过脑子,就是比葫芦画瓢,现在慢慢的懂了,是时间的积累,也是经验的增加,也反映出,知识这东西需要经常温习,需要体会。说不定哪一天都顿悟了呢,只要坚持去学习,或早或晚都会有收获的,慢慢的发现,这个序列化就是套路,Hadoop 支持三个序列化,IntWritable、DoubleWritable和ByteWritable
这里我只是找了其中一个,如若工作需要,根据需要自行调整。