Hadoop基礎-序列化與反序列化(實現Writable接口)


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

  java.serial 文件屬性如下:

  同樣都是對一個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 文件內容

1>.java對自定義Student類實現序列化和反序列化

 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.student";
12     public static void main(String[] args) throws Exception {
13         studentSerialze();
14         studentDeserialize();
15     }
16     //定義序列化方式
17     public static void studentSerialze() throws IOException {
18         //實例化對象yzj
19         Student yzj = new Student();
20         yzj.setName("尹正傑");
21         yzj.setAge(18);
22         yzj.setIsmarry(false);
23         FileOutputStream fos = new FileOutputStream(fileParh);
24         ObjectOutputStream oos = new ObjectOutputStream(fos);
25         //進行Java的序列化方式
26         oos.writeObject(yzj);
27         //釋放資源
28         oos.close();
29         fos.close();    //這里其實可以不用寫,因為上面一行釋放資源會順帶把它封裝的對線下也關流了,不過這行即使咱們寫了也是不會報錯的!
30     }
31     //定義反序列化方法
32     public static void  studentDeserialize() throws Exception {
33         FileInputStream fis = new FileInputStream(fileParh);
34         ObjectInputStream ois = new ObjectInputStream(fis);
35         //調用反序列化流的方法"readObject()"讀取對象,要注意的是反序列話的對象需要存在相應的字節碼文件。否則會拋異常
36         Object res = ois.readObject();
37         //釋放資源
38         ois.close();
39         fis.close();
40         System.out.println(res);
41     }
42 }
43 
44 
45 /*
46 以上代碼執行結果如下:
47 Student{name='尹正傑', age=18, ismarry=false}
48 */

2>.Hadoop對自定義Student類實現序列化和反序列化

  Hadoop對自定義類實現序列化或者反序列化操作的話,需要實現Hadoop的Writable接口,接下來我們舉個例子,代碼如下:

 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 org.apache.hadoop.io.Writable;
10 
11 import java.io.DataInput;
12 import java.io.DataOutput;
13 import java.io.IOException;
14 
15 public class StudentWirtable implements Writable {
16 
17     //切記這里需要給student賦值,不然可能會報錯空指針異常喲!
18     private Student student = new Student();
19 
20     public Student getStudent() {
21         return student;
22     }
23 
24     public void setStudent(Student student) {
25         this.student = student;
26     }
27 
28     //定義串行化的方法
29     public void write(DataOutput dataOutput) throws IOException {
30         //定義自定義類的序列化順序,我這里是先序列化name,在序列化age,最好才序列化ismarry。
31         dataOutput.writeUTF(student.getName());
32         dataOutput.writeInt(student.getAge());
33         dataOutput.writeBoolean(student.isIsmarry());
34 
35     }
36 
37     //定義反串行化的方法
38     public void readFields(DataInput dataInput) throws IOException {
39         student.setName(dataInput.readUTF());
40         student.setAge(dataInput.readInt());
41         student.setIsmarry(dataInput.readBoolean());
42     }
43 }

  接下來就是我們調用自己定義的序列化方法啦,測試代碼如下:

 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 HadoopSerial {
11     public final static String fileParh = "D:\\10.Java\\IDE\\yhinzhengjieData\\hadoop.student";
12     public static void main(String[] args) throws IOException {
13         studentSerialze();
14         studentDeserialize();
15     }
16 
17     //定義序列化方式
18     public static void studentSerialze() throws IOException {
19         //實例化對象yzj
20         Student yzj = new Student();
21         yzj.setName("尹正傑");
22         yzj.setAge(18);
23         yzj.setIsmarry(false);
24         //初始化StudentWirtable,這是咱們定義的一個容器
25         StudentWirtable sw = new StudentWirtable();
26         sw.setStudent(yzj);
27         FileOutputStream fos = new FileOutputStream(fileParh);
28         DataOutputStream dos = new DataOutputStream(fos);
29         //進行Hadoop的序列化方式
30         sw.write(dos);
31         //別忘記釋放資源喲
32         dos.close();
33         fos.close();
34     }
35 
36     //定義反序列化方式
37     public static void  studentDeserialize() throws IOException {
38         //初始化intWritable
39         StudentWirtable sw = new StudentWirtable();
40         DataInputStream dis = new DataInputStream(new FileInputStream(fileParh));
41         sw.readFields(dis);
42         Student yzj = sw.getStudent();
43         dis.close();
44         System.out.println(yzj.toString());
45 
46     }
47 }
48 
49 /*
50 以上代碼執行結果如下:
51 Student{name='尹正傑', age=18, ismarry=false}
52  */

3>.查看兩種方式的序列化文件大小

   hadoop.student 文件屬性如下:

  java.student 文件屬性如下:

  如果一個int類型你感覺不出來hadoop序列化和java序列化的區別,那么自定義類的屬性進行序列化你應該明顯的看出來hadoop序列化要比java傳統的序列化方式要節省空間多的多,如果這個數據換成一個PB的大小的話,估計差距就是天壤之別啦!

 

 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM