【Hadoop源码解析】Hadoop WritableUtils解析

举报
想要一只猫 发表于 2021/01/12 17:50:36 2021/01/12
【摘要】 本章讲解了Hadoop WritableUtils的主要代码实现

WritableUtils简介

Hadoop WritableUtils是Hadoop开发中读写文件的常用工具,一般使用方式为如下:

    FileSystem rfs = ((LocalFileSystem)FileSystem.getLocal(job)).getRaw();

    // 写数据
    FSDataOutputStream out = rfs.create(filepath); //写数据流
    WritableUtils.writeVInt(out, intVal);
    WritableUtils.writeVLong(out, longVal);
    WritableUtils.writeString(out, stringVal);
    WritableUtils.writeEnum(out, enumVal);

    // 读数据
    FSDataInputStream in = rfs.open(filepath); //读数据流
    int intVal = WritableUtils.readVInt(in);
    long longVal = WritableUtils.readVLong(in);

WritableUtils对读写数据做了很好的封装,特别对读写int、long型数据还有压缩。

writeVInt

writeVInt其实还是用的writeVLong。

  public static void writeVInt(DataOutput stream, int i) throws IOException {
    writeVLong(stream, i);
  }

writeVLong

下面是writeVLong的代码解析,逻辑很清晰,对于大于等于-112且小于等127的数据会直接写入,-113~-128用来标识其他数据的符号、字节长度。

  public static void writeVLong(DataOutput stream, long i) throws IOException {
    // 对于大于等于-112且小于等于127的数据直接以字节形式写入
    if (i >= -112 && i <= 127) {
      stream.writeByte((byte)i);
      return;
    }
    
    //  len用来确定最终写入的字节长度
    //  -113~-120表示大于127的1~8字节长度的数据
    //  -121~-128表示小于-112的1~8字节长度的数据(注意这个数据是原数据与-1L(即全1)异或后的,读的时候做相应操作) 
    int len = -112;
    if (i < 0) {
      i ^= -1L; // take one's complement'
      len = -120;
    }
    // 判断数据要占多少个字节,注意tmp第一次必然不为0。
    long tmp = i;
    while (tmp != 0) {
      tmp = tmp >> 8;
      len--;
    }
    // 先写入len用来标识数据的符号、字节长度  
    stream.writeByte((byte)len);
    // 用来判断写入多少个字节
    len = (len < -120) ? -(len + 120) : -(len + 112);
    // 先写高位数据   
    for (int idx = len; idx != 0; idx--) {
      int shiftbits = (idx - 1) * 8;
      long mask = 0xFFL << shiftbits;
      stream.writeByte((byte)((i & mask) >> shiftbits));
    }
  }

readVInt

显然readVInt必然用了readVLong,在获得数据后对数据的值域做判断。

  public static int readVInt(DataInput stream) throws IOException {
    long n = readVLong(stream);
    if ((n > Integer.MAX_VALUE) || (n < Integer.MIN_VALUE)) {
      throw new IOException("value too long to fit in integer");
    }
    return (int)n;
  }

readVLong

readVLong也很清晰,即writeVLong反向操作即可。

  public static long readVLong(DataInput stream) throws IOException {
    //  先读取一个字节
    byte firstByte = stream.readByte();
    //  如果字节大于等于-112,则返回1,否则返回后续字节长度+1(因为1被占了,所以需要+1)
    int len = decodeVIntSize(firstByte);
    if (len == 1) {
      return firstByte;
    }
    long i = 0;
    // writeVLong的反向操作
    for (int idx = 0; idx < len-1; idx++) {
      byte b = stream.readByte();
      i = i << 8;
      i = i | (b & 0xFF);
    }
    return (isNegativeVInt(firstByte) ? (i ^ -1L) : i);
  }

  public static int decodeVIntSize(byte value) {
    if (value >= -112) {
      return 1;
    } else if (value < -120) {
      return -119 - value;
    }
    return -111 - value;
  }
【版权声明】本文为华为云社区用户原创内容,转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息, 否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。