13

C#'sBinaryReader有一个函数,根据 MSDN,读取编码为“七位整数”的整数,然后读取具有该整数长度的字符串。

是否有关于七位整数格式的明确文档(我粗略了解 MSB 或 LSB 标记是否有更多字节要读取,其余位是数据,但我会很高兴更准确的)。

更好的是,是否有一种C以这种格式读写数字的实现?

4

6 回答 6

17

好吧,BinaryReader.Read7BitEncodedInt的文档已经说过,它希望使用BinaryWriter.Write7BitEncodedInt写入值,并且该方法文档详细说明了格式:

value 参数的整数一次写入 7 位,从 7 个最低有效位开始。一个字节的高位表示在这个字节之后是否还有更多字节要写入。

如果值适合七位,则只占用一个字节的空间。如果值不适合七位,则在第一个字节上设置高位并写出。然后将值移动七位并写入下一个字节。重复这个过程,直到整个整数都被写入。

所以整数 1259551277,二进制 1001011000100110011101000101101 将被转换为 7 位格式,如下所示:

Remaining integer                 encoded bytes
1001011000100110011101000101101
100101100010011001110100          00101101
10010110001001100                 10101101 01110100
1001011000                        10101101 11110100 01001100
100                               10101101 11110100 11001100 01011000
0                                 10101101 11110100 11001100 11011000 00000100

不过,我现在对自己的 C 语言技能并没有那么有信心提供一个可行的实现。但根据那个描述,这并不是很难做到。

于 2009-10-11T12:16:00.820 回答
7

基本上,7 位编码背后的想法Int32是减少小值所需的字节数。它是这样工作的:

  1. 取原始值的前 7 个最低有效位。
  2. 如果这个值超过了这 7 位可以容纳的值,则第 8 位设置为 1,表示必须读取另一个字节。否则该位为 0,读取到此结束。
  3. 读取下一个字节,将其值左移 7 位并与先前读取的值进行或运算以将它们组合在一起。同样,该字节的第 8 位指示是否必须读取另一个字节(将读取的值再移动 7 次)。
  4. 这一直持续到最多读取 5 个字节(因为即使Int32.MaxValue从每个字节中仅窃取 1 位,也不需要超过 5 个字节)。如果第 5 个字节的最高位仍然设置,则您读取的内容不是 7 位编码的 Int32。

请注意,由于它是逐字节写入的,因此对于这些值而言,字节顺序根本不重要。对于给定的值范围,需要以下字节数:

  • 1 个字节:0 到 127
  • 2 个字节:128 到 16,383
  • 3 个字节:16,384 到 2,097,151
  • 4 个字节:2,097,152 到 268,435,455
  • 5 个字节:268,435,456 到 2,147,483,647 ( Int32.MaxValue) 和 -2,147,483,648 ( Int32.MinValue) 到 -1

正如你所看到的,实现有点愚蠢,负值总是需要 5 个字节,因为符号位是原始值的第 32 位,总是在第 5 个字节结束。

因此,我不建议将它用于负值或大于 ~250,000,000 的值。我只看到它在内部用于 .NET 字符串的字符串长度前缀(您可以使用BinaryReader.ReadStringand读取/写入的字符串BinaryReader.WriteString),描述字符串所包含的字符数,只有正值。

虽然您可以查找原始 .NET 源代码,但我在BinaryData 库中使用了不同的实现。

于 2018-04-11T16:29:07.870 回答
6

我还必须探索这种 7 位格式。在我的一个项目中,我使用 C# 的 BinaryWriter 将一些数据打包到文件中,然后使用 BinaryReader 再次解压,效果很好。

后来我还需要为这个项目的 Java 打包文件实现一个阅读器。Java 有一个名为 DataInputStream 的类(在 java.io 包中),它有一些类似的方法。不幸的是,DataInputStream 的数据解释与 C# 非常不同。

为了解决我的问题,我自己通过编写一个扩展 java.io.DataInputStream 的类将 C# 的 BinaryReader 移植到 Java。这是我写的方法,它和 C# 的 BinaryReader.readString() 完全一样:

public String csReadString() throws IOException {
    int stringLength = 0;
    boolean stringLengthParsed = false;
    int step = 0;
    while(!stringLengthParsed) {
        byte part = csReadByte();
        stringLengthParsed = (((int)part >> 7) == 0);
        int partCutter = part & 127;
        part = (byte)partCutter;
        int toAdd = (int)part << (step*7);
        stringLength += toAdd;
        step++;
    }
    char[] chars = new char[stringLength];
    for(int i = 0; i < stringLength; i++) {
        chars[i] = csReadChar();
    }
    return new String(chars);
}
于 2011-05-17T00:08:09.933 回答
5
/*
 * Parameters:  plOutput[out] - The decoded integer
 *              pbyInput[in]  - Buffer containing encoded integer
 * Returns:     Number of bytes used to encode the integer
 */
int SevenBitEncodingToInteger(int *plOutput, char *pbyInput)
{
    int lSize = 0;
    int lTemp = 0;
    while(true)
    {
        lTemp += pbyInput[lSize] & 0x7F;
        if(pbyInput[lSize++] > 127)
            lTemp <<= 7;
        else
            break;
    }
    *plOutput = lTemp;
    return lSize;
}
于 2011-07-29T09:51:09.877 回答
3

此处描述了格式:http: //msdn.microsoft.com/en-us/library/system.io.binarywriter.write7bitencodedint.aspx

于 2009-10-11T12:18:45.430 回答
2

Write7BitEncodedInt 方法包含描述:每个字节的最低 7 位编码数字的下 7 位。当后面有另一个字节时,最高位被设置。

于 2009-10-11T12:18:22.810 回答