Hadoop中Writable類之三


1.BytesWritable

<1>定義

ByteWritable是對二進制數據組的封裝。它的序列化格式為一個用於指定后面數據字節數的整數域(4個字節)后跟字節本身

舉個例子,假如有一個數組bytes,里面有兩個byte,bytes[0]=3,bytes[1]=5,那么,數組序列化后,其返回一個字節數組,序列化方面,可以查看我的博客Hadoop序列化  ,那么序列化后,其返回一個字節書組byteSeri,byteSeri里面有多少個字節?

分析:

在定義里指出,序列化格式為一個整數域字節本身

  • 整數域是用來指定后面數據的字節數,我們知道byte[0],和byte[1]是兩個字節,所以,整數域的二進制為:00000000 00000000 00000000 00000010(4個字節),以16進制表示:00 00 00 02
  • 字節本身就是byte[0]和byte[1]這兩個字節,所以,字節本身的二進制表示為:00000011 00000101,以16進制表示為:03 05
  • 整個序列化數組的二進制表示為:00000000 00000000 00000000 00000010    00000011 00000101 ,以16進制表示為:00 00 00 02 03 05

那么上述的序列化后數組的長度為字節的個數,也就是 4 + 2 =6;拿例子來驗證:

Example:

 1 package cn.roboson.writable;
 2 
 3 import java.io.ByteArrayOutputStream;
 4 import java.io.DataOutputStream;
 5 import java.io.IOException;
 6 
 7 import org.apache.hadoop.io.BytesWritable;
 8 import org.apache.hadoop.io.Writable;
 9 import org.apache.hadoop.util.StringUtils;
10 
11 /**
12  * 1.定義一個二進制字節數組
13  * 2.將其序列化
14  * 3.由其序列化格式分析其內容
15  * @author roboson
16  *
17  */
18 
19 public class WritableText05 {
20     
21     public static void main(String[] args) throws IOException {
22         //定義一個二進制字節數組
23         BytesWritable b = new BytesWritable(new byte[]{3,5});
24         
25         //輸出其長度,很明顯,只有兩個字節,其長度肯定是2
26         System.out.println("二進制數組的長度:"+b.getLength());
27         
28         //將其序列化,序列化可以查看我的博客《Hadoop序列化》
29         byte[] bytes=serialize(b);
30         //在上面的分析中,16進制的輸出為:00 00 00 02 03 05
31         System.out.println("序列化后以16進制表示:"+StringUtils.byteToHexString(bytes));
32         
33         //在上面的分析中,序列化后的數組長度為:6
34         System.out.println("序列化后的長度:"+bytes.length);
35     }
36     
37     public static byte[] serialize(Writable writable) throws IOException{
38         ByteArrayOutputStream out = new ByteArrayOutputStream();
39         DataOutputStream dataOut = new DataOutputStream(out);
40         writable.write(dataOut);
41         return out.toByteArray();
42         
43     }
44 }

運行結果:

<2>可變性

和Text相似,BytesWritable是可變的,可以通過set()方法,設置進行修改。BytesWritable的getBytes()方法,返回的是字節數組的容量,而其存儲數據的實際大小,需要通過getLong()方法來查看

Example:

 1 package cn.roboson.writable;
 2 
 3 import org.apache.hadoop.io.BytesWritable;
 4 
 5 public class WritableText06 {
 6     
 7     public static void main(String[] args) {
 8         BytesWritable b = new BytesWritable(new byte[]{3,5});
 9         System.out.println("字節數組的實際數據長度:"+b.getLength());
10         System.out.println("字節數組的容量大小:"+b.getBytes().length);
11         
12         //改變其容量
13         b.setCapacity(11);
14         //getLength()方法,返回的是實際數據的大小
15         System.out.println("改變容量后實際數據的大小:"+b.getLength());
16         //getBytes().length返回的是容量大小
17         System.out.println("改變容量后容量的大小:"+b.getBytes().length);
18     }
19 }

 

運行結果:

 

 

2.NullWritable

NullWritable是Writable的一個特殊類型,它的序列化長度為0.它並不從數據流中讀取數據,也不寫入數據。它充當占位符;在MapReduce中,如果不需要使用健或者值,就可以將健或者值聲明為NullWritable——結果是存儲常量空值。

NullWritable是一個單例實例類型,可以通過靜態方法get()獲得其實例,public static NullWritable get() ;

Example:

 1 package cn.roboson.writable;
 2 
 3 import java.io.ByteArrayOutputStream;
 4 import java.io.DataOutputStream;
 5 import java.io.IOException;
 6 
 7 import org.apache.hadoop.io.NullWritable;
 8 import org.apache.hadoop.io.Writable;
 9 /**
10  * 1.獲得一個NullWritable
11  * 2.序列化后,查看其長度
12  * @author roboson
13  *
14  */
15 
16 public class Writable02 {
17     
18     public static void main(String[] args) throws IOException {
19         
20         NullWritable writable = NullWritable.get();
21         byte[] bytes = serialize(writable);
22         System.out.println("NullWritable序列化后的長度:"+bytes.length);
23     }
24     
25     public static byte[] serialize(Writable writable) throws IOException{
26         ByteArrayOutputStream out = new ByteArrayOutputStream();
27         DataOutputStream dataOut = new DataOutputStream(out);
28         writable.write(dataOut);
29         return out.toByteArray();
30         
31     }
32 }

 

運行結果:

 

3.ObjectWritable

ObjectWritable是對Java基本類型(String、enum,Writable,null或這些類型組成的數組)的通用封裝。在Hadoop RPC中用於對方法的參數和返回類型進行封裝和解封裝。當一個字段中包含多個類型時,ObjectWritable是非常有用的,可以直接將類型聲明為ObjectWritable,但是,缺陷是非常浪費空間。舉個例子來看看,就知道有多么浪費!

Example:

 1 package cn.roboson.writable;
 2 
 3 import java.io.ByteArrayOutputStream;
 4 import java.io.DataOutputStream;
 5 import java.io.IOException;
 6 
 7 import org.apache.hadoop.io.BytesWritable;
 8 import org.apache.hadoop.io.ObjectWritable;
 9 import org.apache.hadoop.io.Writable;
10 import org.apache.hadoop.util.StringUtils;
11 
12 /**
13  * 1.新建一個ObjectWritable
14  * 2.將其序列化並查看其大小
15  * @author roboson
16  *
17  */
18 public class Writable03 {
19     
20     public static void main(String[] args) throws IOException {
21         
22         BytesWritable bytes = new BytesWritable(new byte[]{3,5});
23         byte[] byte1 = serialize(bytes);
24         //前面的介紹,可以知道,長度為6
25         System.out.println("bytes數組序列化后的長度:"+byte1.length);
26         System.out.println("bytes數組序列化的16進制表示:"+StringUtils.byteToHexString(byte1));
27         
28         ObjectWritable object = new ObjectWritable();
29         object.set(new byte[]{3,5});
30         byte[] byte2 = serialize(object);
31         System.out.println("ObjectWritable序列化后的長度:"+byte2.length);
32         System.out.println("ObjectWritable列化的16進制表示:"+StringUtils.byteToHexString(byte2));
33     }
34     
35     public static byte[] serialize(Writable writable) throws IOException{
36         ByteArrayOutputStream out = new ByteArrayOutputStream();
37         DataOutputStream dataOut = new DataOutputStream(out);
38         writable.write(dataOut);
39         return out.toByteArray();
40         
41     }
42 }

 

運行結果:

 

4.GenericWritable

通過上面的運行結果,已經知道ObjectWritable類是非常浪費空間的,如果封裝的類型數量比較少,這種情況下,可以用GenericWritable類來代替。它的效率更高一些。因為對序列化后的類型的引用加入位置索引。查看HadoopAPI幫助文檔,發現GenericWritable是一個抽象類:

 

那么如何使用它:

  • 寫一個類,繼承自GenericWritable
  • 重寫getTypes()方法
  • 指定靜態類型數組中的值

Example:

MyGenericWritable.java

package cn.roboson.writable;

import org.apache.hadoop.io.BytesWritable;
import org.apache.hadoop.io.GenericWritable;
import org.apache.hadoop.io.IntWritable;
import org.apache.hadoop.io.Text;
import org.apache.hadoop.io.Writable;

public class MyGenericWritable extends GenericWritable{

    private static Class[] CLASSES={
        Text.class,
        BytesWritable.class,
        IntWritable.class
    };
    @Override
    protected Class<? extends Writable>[] getTypes() {
        // TODO Auto-generated method stub
        return CLASSES;
    }

}

 

  Writable04.java

 1 package cn.roboson.writable;
 2 
 3 import java.io.ByteArrayOutputStream;
 4 import java.io.DataOutputStream;
 5 import java.io.IOException;
 6 
 7 import org.apache.hadoop.io.BytesWritable;
 8 import org.apache.hadoop.io.IntWritable;
 9 import org.apache.hadoop.io.Text;
10 import org.apache.hadoop.io.Writable;
11 import org.apache.hadoop.util.StringUtils;
12 
13 public class Writable04 {
14     
15     public static void main(String[] args) throws IOException {
16         
17         Text t = new Text("Hadoop");
18         byte[] byte0 = serialize(t);
19         System.out.println("Text序列化后的長度:"+byte0.length);
20         System.out.println("Text序列化的16進制表示:"+StringUtils.byteToHexString(byte0));
21         
22         MyGenericWritable genericText = new MyGenericWritable();
23         genericText.set(t);
24         byte[] byteText = serialize(genericText);
25         System.out.println("TextGenericWritable序列化后的長度:"+byteText.length);
26         System.out.println("TextGenericWritable列化的16進制表示:"+StringUtils.byteToHexString(byteText));
27         
28         BytesWritable bytes = new BytesWritable(new byte[]{3,5});
29         byte[] byte1 = serialize(bytes);
30         //前面的介紹,可以知道,長度為6
31         System.out.println("bytes數組序列化后的長度:"+byte1.length);
32         System.out.println("bytes數組序列化的16進制表示:"+StringUtils.byteToHexString(byte1));
33         
34         MyGenericWritable generic = new MyGenericWritable();
35         generic.set(bytes);
36         byte[] byteBytes = serialize(generic);
37         System.out.println("GenericWritable序列化后的長度:"+byteBytes.length);
38         System.out.println("GenericWritable列化的16進制表示:"+StringUtils.byteToHexString(byteBytes));
39         
40 
41         IntWritable intWritable = new IntWritable(2);
42         byte[] byte2 = serialize(intWritable);
43         System.out.println("IntWritable序列化后的長度:"+byte2.length);
44         System.out.println("IntWritable序列化的16進制表示:"+StringUtils.byteToHexString(byte2));
45         
46         MyGenericWritable genericInt = new MyGenericWritable();
47         genericInt.set(intWritable);
48         byte[] byteInt = serialize(genericInt);
49         System.out.println("IntGenericWritable序列化后的長度:"+byteInt.length);
50         System.out.println("IntGenericWritable列化的16進制表示:"+StringUtils.byteToHexString(byteInt));
51         
52     }
53     public static byte[] serialize(Writable writable) throws IOException{
54         ByteArrayOutputStream out = new ByteArrayOutputStream();
55         DataOutputStream dataOut = new DataOutputStream(out);
56         writable.write(dataOut);
57         return out.toByteArray();
58         
59     }
60 }

 

運行結果:

 

 

可以發現,GenericWritable比ObjectWritable更節省空間,和本來的相比,只增加了一個字節,並且這個字節是其在靜態數組CLASSES的下標號!


免責聲明!

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



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