从提供的InputStream中读取一个可变长度的整数

时间:2017-03-30 13:23:17

标签: java utf-8 stream bit-manipulation inputstream

我看起来有点高于Netflix Hollow库代码(https://github.com/Netflix/hollow),我发现这个功能我找不到任何意义(警告:我对Java不太了解)。 从理论上讲,该函数从InputStream中返回一个可变长度的整数。

/**
 * Read a variable length integer from the supplied InputStream
 */
public static int readVInt(InputStream in) throws IOException {
    byte b = (byte)in.read();

    if(b == (byte) 0x80)
        throw new RuntimeException("Attempting to read null value as int");

    int value = b & 0x7F;
    while ((b & 0x80) != 0) {
      b = (byte)in.read();
      value <<= 7;
      value |= (b & 0x7F);
    }

    return value;
}

我评论我的怀疑:

1) Int值= b&amp; 0x7F :结果总是b,对吗?有什么意义?

2) while((b&amp; 0x80)!= 0) b&amp;的结果0x80 (如果b是整数位,即从0到9的十进制编码,十进制为48-57)始终为0.因此,永远不会进入循环...

2 个答案:

答案 0 :(得分:2)

老实说,在Java中找到这样的低级实现是很奇怪的(IMHO);这种逻辑在C程序和其他接近金属的程序中更常见。语言。但我认为向数百万用户提供有效的流媒体并不是免费的:)

bbyte,不是整数。它被解释为8位 0x8010000000,除了高阶(&#34;第一个&#34;)之外,所有位都设置为零的掩码。
0x7F01111111,一个掩码,除第一个之外,所有位都设置为1。 0x80的倒数 value是我们想要读取的整数值。这是一个int,在Java中是4个字节。最初是00000000000000000000000000000000

代码逐个读取字节序列。它使用第一位作为终止标记(0表示&#34;最后一个字节&#34;),并将其他7位连接到value。应用掩码来评估这些位。因此b & 0x80用于检查第一位是否设置,而b & 0x7F用于将第一位设置为零并保留所有其他位的值。

示例:

  • 我们希望每个字节传输24612135字节。这是二进制的1011101111000110100100111
  • 我们将它分成7位组:0001011 1011110 0011010 0100111并使每组成为1个前导的8位字节,除了最后一个将被标记为0前导的字节:10001011 11011110 10011010 00100111 < / LI>
  • 读取第一个字节。所以b = 10001011。由于这不是0x8010000000),我们知道这将是一个有效的非空整数。
  • 我们丢弃第一位(b & 0x7f00001011)并将value设置为该位。现在value00000000000000000000000000001011
  • 现在这可能是一个单字节的数字,所以我们必须检查第一位,知道我们是否应该继续阅读。 b & 0x80不为0,因此我们进入循环以读取更多字节。
  • 读取第二个字节。现在b = 11011110。丢弃第一位(b & 0x7f)并将其他7位置于value内。但是value已经设置了一些位,所以我们必须将它们移位以为7位以上腾出空间:value <<= 7。现在value00000000000000000000010110000000。通过使用按位OR运算符value |= (b & 0x7F),我们将最低的7位设置为正确的值。现在value00000000000000000000010111011110
  • 第二个字节也没有将第一个位设置为0,所以我们再次循环第三个字节。相同的逻辑;现在value00000000000000101110111100011010
  • 第三个字节也没有将第一个位设置为0;再次循环第四个字节00100111。现在value00000001011101111000110100100111。这是我们打算发送的正确值。
  • 因为第四个字节确实将第一个位设置为零,所以循环的中断条件现在计算为true,所以我们停止读取字节。

无论如何,我希望这能帮到你。

答案 1 :(得分:0)

重点是:他们可能正在使用他们自己的&#34;确定如何使用流写入读取值的协议。

在该协议中,值0x80具有特殊含义:&#34;值结束&#34;。

意义:&#34;作家&#34;部分写入一个字节序列,然后输入一个0x​​80表示不再跟随字节。然后:

while ((b & 0x80) != 0) {
0x8时,

评估为 false ?被读了。含义:如果设置了第一位,则&#34;消息结束&#34;。

换句话说:当你想从那个流中读取一个int时;你得到的第一个字节是0x80 - 然后:&#34;你的&#34;没有值;因此例外。

然后你只是逐字节读;然后将这些字节移到结果int值中 - 直到0x80&#34;结束值&#34;标记字节进来。