【Hadoop源码解析】Hadoop WritableUtils解析
【摘要】 本章讲解了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)