我有一些文件,其中每7位代表一个小尾数整数。
到目前为止,我有一个实现将字节读入字节数组,转换为字符串,使用循环索引将7个字符放入BitArray中,并根据其索引进行2 ^ x的实现,但这似乎非常慢(文件仅20KB,但要花费5分钟以上的时间来解析),而且转换过多也是最佳方法。
有没有一种方法可以直接从文件中读取一组7位?
最佳答案
如果未打包这些7位整数,则只需处理每个字节的最低有效7位即可:
Byte b; Int32 nb;
while( (nb = reader.ReadByte()) != -1 ) {
b = (Byte)nb;
Byte value = b & 0x7F;
yield return value;
}
如果这些是打包字节,那么会更有趣:)
您将需要1到2个字节来提取值。我假设输入是
Byte
的流(为简化API,使用IEnumerator
表示),其中7位的压缩方式如下:7-bit |0 |1 |2 |3 |4
Bytes |0 |1 |2 |3
Bits |0 |1 |2 |3 |4 |5 |6 |7 |0 |1 |2 |3 |4 |5 |6 |7 |0 |1 |2 |3 |4 |5 |6 |7 |0
该算法是这样的:
保持一个“位索引”(
bi
),该位告诉我们下一个7位整数开始的位偏移量(每个字节中)。读取一个字节(
b0
),采用前7位并将其返回。将位索引增加7。
7 + 7大于8(一个字节的大小),因此我们需要另一个字节。读入另一个字节并将此(
b1
)与前一个字节(b0
)合并为一个16位值,该值可以一次读取通过从中读取下一个7位值(
bi + 7
)来提取下一个7位值,将其移位以使其有用,然后将其返回。重复。
这里可能存在一些错误,如果您发现任何错误,请告诉我!
public static IEnumerable<Byte> ReadPacked7BitInts(IEnumerator<Byte> inputBytes) {
Int32 bi = 0; // bit-index
if( !inputBytes.MoveNext() ) yield break;
Byte b0 = inputBytes.Current;
while( true ) {
if( bi == 0 ) yield return b0 & 0x7F;
if( bi == 1 ) yield return (b0 >> 1) & 0x7F;
else {
// Read another byte
if( !inputBytes.MoveNext() ) yield break;
Byte b1 = inputBytes.Current;
UInt16 value = (UInt16)b0 | ((UInt16)b1 << 8);
yield return ( value >> bi ) & 0x7F;
}
bi = (bi + 7) % 8;
}
}