zoukankan      html  css  js  c++  java
  • 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的下标号!

  • 相关阅读:
    DS博客作业03--栈和队列
    DS博客作业02--线性表
    DS博客作业01--日期抽象数据类型设计与实现
    C语言博客作业06--结构体&文件
    DS博客作业08--课程总结
    DS博客作业07--查找
    DS博客作业06--图
    DS博客作业05--树
    DS博客大作业--树 (陈梓灿组)
    DS博客作业03--栈和队列
  • 原文地址:https://www.cnblogs.com/robert-blue/p/4164975.html
Copyright © 2011-2022 走看看