以C-BinaryReader.ReadString的7位格式编码整数
C#
的BinaryReader
有一个函数,根据MSDN,读取一个编码为“七位整数”的整数,然后读取一个长度为整数的字符串。
是否有一个清晰的七位整数格式文档(我粗略地了解MSB或LSB标记是否有更多字节要读取,其余位是数据,但我会很高兴更精确的东西)。
更好的是,是否有以这种格式读写数字的C
实现?
好吧, BinaryReader.Read7BitEncodedInt的文档已经说过,它希望用BinaryWriter.Write7BitEncodedInt写入该值,并且该方法文档详细说明了这种格式:
值参数的整数一次写入7位,从7个最低有效位开始。 字节的高位表示在此字节之后是否有更多字节要写入。
如果值适合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
不过,我现在对我的C技能没有那么自信来提供一个有效的实现。 但根据这种描述,这并不是很难做到。
我还必须探索这种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); }
/* * 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; }
Write7BitEncodedInt方法包含描述:每个字节的最低7位编码该数字的后7位。 当跟随另一个字节时,设置最高位。
格式如下所述: http : //msdn.microsoft.com/en-us/library/system.io.binarywriter.write7bitencodedint.aspx
基本上,7位编码Int32
背后的想法是减少小值所需的字节数。 它的工作原理如下:
- 获取原始值的前7个最低有效位。
- 如果该值超过这7位的值,则第8位设置为1,表示必须读取另一个字节。 否则该位为0并且读取在此处结束。
- 读取下一个字节,将其值向左移7位,并将其与先前读取的值进行“或”运算,将它们组合在一起。 同样,该字节的第8位指示是否必须读取另一个字节(将读取值进一步移位7次)。
- 这一直持续到最多读取5个字节为止(因为当每个字节只有1位被盗时,甚至
Int32.MaxValue
也不需要超过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库中使用了不同的实现。