以C-BinaryReader.ReadString的7位格式编码整数

Ela*_*ich 12 .net c# binary serialization 7-bit

C#BinaryReader具有这样的功能,根据MSDN,读取编码为'7个整数’的整数,并且然后读出与该整数的长度的字符串.

是否有一个明确的七位整数格式文档(我粗略地了解MSB或LSB标记是否有更多字节要读取,其余位是数据,但我会很高兴更精确的东西).

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

Joe*_*oey 13

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

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

如果value适合7位,则只需要一个字节的空间.如果值不适合7位,则在第一个字节上设置高位并写出.然后将值移位7位并写入下一个字节.重复此过程,直到写入整个整数.

因此,二进制1001011000100110011101000101101中的整数1259551277将转换为该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
Run Code Online (Sandbox Code Playgroud)

不过,我现在对我的C技能没有那么自信来提供一个有效的实现.但基于这种描述,这并不是很难做到.

  • 仅供参考:这些方法在 .NET 5 之前一直处于“受保护”状态,在 .NET 5 中它们变为“公共”。 (2认同)

Ale*_* B. 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);
}
Run Code Online (Sandbox Code Playgroud)


Ray*_*Ray 6

基本上,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.ReadString和读取/写入BinaryReader.WriteString的字符),它描述了组成字符串的字符数,仅具有正值。

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


小智 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;
}
Run Code Online (Sandbox Code Playgroud)