如何一次读取14位二进制文​​件而不是8位?

时间:2013-03-22 23:14:18

标签: c binary compression bit-manipulation

我需要解压缩二进制文件。由于二进制文件以14位编码,因此我必须读取14位而不是8位才能进行解码。但据我所知,使用getc()读取文件时,每次只给我8位。有没有有效的方法来实现这一目标?下面是一个可以完成工作的代码块,但它看起来效率不高,我该如何改进呢?

unsigned int input_code(FILE *input)
{
    unsigned int return_value;
    static int input_bit_count=0;
    static unsigned long input_bit_buffer=0L;

    while (input_bit_count <= 24)
    {
        input_bit_buffer |= 
            (unsigned long) getc(input) << (24-input_bit_count);
        input_bit_count += 8;
    }

    return_value=input_bit_buffer >> (32-BITS);
    input_bit_buffer <<= BITS;
    input_bit_count -= BITS;
    return(return_value);
}

3 个答案:

答案 0 :(得分:4)

一般来说,尽管标准库和O / S中的缓冲代码可以弥补这一点,但您应该避免读取数据量很小,因为它效率很低。

更好的理由是它会导致奇怪和不自然的代码。为什么不一次读取112位= 14个字节 - 这是8的倍数和14的倍数。然后,您可以将生成的缓冲区视为8个14位数据。事情很顺利。

但是,如果你绝对必须一次读取尽可能少的字节,读取16位,然后吃掉(即处理)其中的14个,读取另外16个,将它们与2个结合起来已经阅读,吃14,并重复这个过程。有关如何执行此类操作的提示,请查看base64编码器/解码器。

答案 1 :(得分:1)

每个输入/输出char或int的几条指令的开销很可能是微不足道的。除非你在这里确定瓶颈,否则不要尝试优化这段代码。

此外,如果我是你,我会检查getc()返回的值。它可以返回EOF而不是数据。

另外,严格地说,char(或C的字节)中有CHAR_BIT位,可以大于8位。

答案 2 :(得分:0)

一次读取的字节数不能少于一个字节。但是,您可以使用位掩码和移位操作将最后两位设置为0(如果要存储16位),并携带您为下一个值删除的两个未使用的位。这可能会使解码操作变得更加复杂和昂贵。

如何将值8解码为8(您可以读取14个字符= 112位= 8 * 14位)?我没有测试过这段代码,可能还有一些拼写错误。它确实编译但我没有你的文件来测试它:

#include <stdio.h>

int main(){
    FILE *file = fopen ("...", "rt");

    // loop variable
    unsigned int i;

    // temporary buffer
    char buffer[14];

    // your decoded ints
    int decoded[8];

    while(fgets(buffer, 14, file) != NULL) {
        int cursor = 0;

        // we do this loop only twice since the offset resets after 4 * 14
        for(i = 0; i <= 4; i+= 4){
            // first decoded int is 16 bits
            decoded[i+0] = (buffer[cursor++] | (buffer[cursor++] << 8));
            // second is 2 + 8 + 8 = 18 bits (offset = 2)
            decoded[i+1] = (decoded[i+0] >> 14) | buffer[cursor++] << 2 | buffer[cursor++] << 10;
            // third is 4 + 8 + 8 = 20 bits (offset = 4)
            decoded[i+2] = (decoded[i+1] >> 14) | buffer[cursor++] << 4 | buffer[cursor++] << 12;
            // next is 6 + 8 = 14 bits (offset = 6)
            decoded[i+3] = (decoded[i+2] >> 14) | buffer[cursor++] << 6;
        }

        // trim the numbers to 14 bits
        for(i = 0; i < 8; ++i)
            decoded[i] &= ((1 << 15) - 1);
    }
    fclose(file);
}

请注意,我对解码的int没有做任何事情,而且我一遍又一遍地写在同一个数组上,这只是一个例子。您可以更多地对代码进行分解,但是我展开了循环并对操作进行了评论,以便您了解它是如何工作的。