更改大型二进制文件中的特定位

Changing specific bit in large binary file

首先,我在 Linux 64 位上处理大型二进制文件 (2-4 GB),该文件也是从另一个进程映射而来的。因此,文件中的内容总是一直在变化。我想在特定 bit/location 处更改一些内容,但不必阅读它。

只改变特定地址的位,不关心其余内容 附加编辑:或将位设置为一直卡住。 (那个位不能改)

我用hexdump看的时候好像是这样的

3ffbd280  00 00 78 32 fb 44 22 cc  44 11 22 aa b2 33 b2 c3

任何想法或想法都非常受欢迎。

FILE* fp = fopen( "bigfile.abc", "rb+" )  
//rb+ is important! see here: the wrong mode may clear/delete the file.
//http://www.cplusplus.com/reference/cstdio/fopen/?kw=fopen

if( fp ) 
{
    unsigned char b = 0;
    fseek( fp, #_of_bytes_from_origin, SEEK_SET )
    fread( &b, 1, 1, fp );      //read 1 unit of 1 byte into 'b'

    b ^= (1<<bit_index);        //toggle the bit, as Jonathan said

    fseek( fp, -1, SEEK_CUR );  //go one byte backwards (you went forwards when reading)
    fwrite( &b, 1, 1, fp );     //write 1 unit of 1 byte back into the file
    fclose(fp);                 //close the file when done
}

这只是我多年来在 32 位机器上使用 C 的经验,但我认为以上任何一项在 64 位架构上都不会改变,因为你明确表示了一个 byte.

参见:http://www.cplusplus.com/reference/cstdio/ 以及核心文件函数:fopen()、fclose()、fseek()、ftell()、fread()、fwrite()

更改特定位:

byte_to_change &= ~(1<<bit_index)

其中 bit_index 是 0 到 7。这​​会将位设置为 0。

byte_to_change |= (1<<bit_index)

将其设置为 1。

对于 64 位 Linux,fseek() 的签名不会造成麻烦; offset 参数是一个 long ,这意味着它将是一个 64 位的数字,它可以轻松处理 2-4 GiB 的文件。如果问题是针对 32 位 Linux 或 64 位 Windows,则情况会有所不同。您在处理 2 GiB 和 4 GiB 之间的偏移量时会遇到问题。

假设打开文件流进行读写。假设位位置是通过文件中的绝对字节偏移加上位号 (0…7) 指定的。假设该位应该改变,因此操作将位从 1 切换到 0 或从 0 到 1。假设不需要在文件中保留当前位置的记录,以便在翻转位后恢复。那么操作顺序可能是:

void flip_bit(FILE *fp, long offset, int bitno)
{
    int c;
    assert(fp != 0);
    assert(offset >= 0);
    assert(bitno >= 0 && bitno < 8);

    fseek(fp, offset, SEEK_SET);
    if ((c = getc(fp)) != EOF)
    {
        c ^= 1 << bitno;
        fseek(fp, -1L, SEEK_CUR);  // Step backwards 1 byte
        putc(c, fp);
        fflush(fp);
    }
}

您更改的每个假设都会触发代码中的相应更改。有必要 fflush(fp); 以最大化在磁盘上进行更改的机会,以便其他进程看到它。此外,fflush(fp) 意味着即使没有中间搜索,也可以安全地将流用于输入(或输出)(ISO/IEC 9899:2011 §7.21.5.3 The fopen 函数, ¶7):

When a file is opened with update mode ('+' as the second or third character in the above list of mode argument values), both input and output may be performed on the associated stream. However, output shall not be directly followed by input without an intervening call to the fflush function or to a file positioning function (fseek, fsetpos, or rewind), and input shall not be directly followed by output without an intervening call to a file positioning function, unless the input operation encounters end of file.

如果您希望确保该位已设置,请将分配替换为:

        c |= 1 << bitno;

如果您希望确保重置该位,请将分配替换为:

        c &= ~(1 << bitno);