首页 > 代码库 > hadoop 中对Vlong 和 Vint的压缩方法

hadoop 中对Vlong 和 Vint的压缩方法

hadoop 中对java的基本类型进行了writeable的封装,并且所有这些writeable都是继承自WritableComparable的,都是可比较的;并且,它们都有对应的get() 和 set()方法,

其中对整型(int 和 long)进行编码的时候,有固定长度格式(intWritable和LongWritable)和可变长度格式(VIntWritable 和 VLongWritable),其中VIntWritable和VLongWritable的编码规则是一样的,

所以VIntWritable的输出可以用VLongWritable读入。其实在VIntWritable的write(DataOUtput out) 与 readFields(DataInput in)中分别调用的是WritableUtils.writeVint(out)和WritableUtils.readVint(int),

而writeVint()和readVint()方法也只是简单的调用了writeVLong和readVLong方法。通过writeVInt()写入的数据自然可以通过readVLong()来进行读人;编码规则如下:

其基本思想  主要思想是大的负数的压缩 ,先反码操作,将负数取反,负数一旦取反,前面的字节就有可能变零了。 然后没八位一组截取成 一个字节

 

写入

  1. public static void writeVLong(DataOutput stream, long i) throws IOException {  
  2. // 如果在一个字节可以表示的范围内 直接返回   
  3.  if (i >= -112 && i <= 127) {  
  4.      stream.writeByte((byte)i);  
  5.      return;  
  6.    }  
  7.     //把负数变成正数   
  8.    int len = -112;  
  9.    if (i < 0) {  
  10.      i ^= -1L; // take one‘s complement‘  
  11.      len = -120;  
  12.    }  
  13.        
  14.   //判断正数有几个位数 通过右移实现  
  15.    long tmp = i;  
  16.    while (tmp != 0) {  
  17.      tmp = tmp >> 8;  
  18.      len--;  
  19.    }  
  20.        
  21.    // 写入第一个字节 该字节标识 这个数十正数还是负数 以及接下来有几个字节属于这个数   
  22.    stream.writeByte((byte)len);  
  23.        
  24.    // 判断需要几个字节表示该数  
  25.    len = (len < -120) ? -(len + 120) : -(len + 112);  
  26.        
  27. //以每八位一组截取 成一个字节   
  28.   
  29.    for (int idx = len; idx != 0; idx--) {  
  30.      int shiftbits = (idx - 1) * 8;  
  31.      long mask = 0xFFL << shiftbits;  
  32.      stream.writeByte((byte)((i & mask) >> shiftbits));  
  33.    }  
  34.  }  

 

读取

  1. public static long readVLong(byte[] bytes, int start) throws IOException {  
  2.     int len = bytes[start];  
  3.     if (len >= -112) {  
  4.       return len;           
  5.     }  
  6.     boolean isNegative = (len < -120);     
  7.     len = isNegative ? -(len + 120) : -(len + 112);     
  8.     if (start+1+len>bytes.length)      
  9.       throw new IOException(  
  10.                             "Not enough number of bytes for a zero-compressed integer");  
  11.     long i = 0;  
  12.     for (int idx = 0; idx < len; idx++) {    
  13.       i = i << 8;  
  14.       i = i | (bytes[start+1+idx] & 0xFF);  
  15.     }  
  16.     return (isNegative ? (i ^ -1L) : i);      
  17.   }