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 }
运行结果: