我有一些文件,其中每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;
    }
}

08-28 12:49