C как читать в одном бите из файла


Я читаю в двоичном файле в C: infile=fopen(input, "rb") и пытаюсь прочитать каждый бит по одному, так что если бы содержимое файла было:

"привет"

Значение ascii 'h' равно 104, поэтому в двоичном виде оно будет 1101000.

Существует ли метод fgetbit (), который можно вызвать и назначить примитивному типу? Пример:

int my_bit=fgetbit(infile); //value of my_bit would be 1 for hello example.
3 2

3 ответа:

Вы не можете получить более детализированный, чем байт во время ввода-вывода файла, но если вы действительно хотите работать на уровне битов, вы можете использовать битовую маску или битовый сдвиг, чтобы изолировать биты, которые вы хотите, как только вы прочитаете байты из файла.

Например, для вывода / проверки каждого отдельного бита в байте:

#include <limits.h> // for CHAR_BIT

...

unsigned char b = 0xA5; // replace with whatever you've read out of your file
for(i = 0; i < CHAR_BIT; i++)
{
    printf("%d", (b>>i)&1); 
}

Чтобы выделить наиболее значимый бит в байте:

unsigned char mask = 0x80; // this value may differ depending on your system's CHAR_BIT
unsigned char value = /* read from file */;
if(value&mask)
{
   // MSB is set
}
else
{ 
   // MSB is clear
}

Вы можете просто прочитать файл в двоичном формате:

FILE *fp;
fp = fopen(input, "rb");

И затем, вы можете получить отдельные биты, используя что-то вроде этого:

bool getBit(unsigned char byte, int position) // position can be 0-7
{
    return (byte >> position) & 0x1;
}

Как все вам говорили, в C.{[12] нет функций доступа к битам.]} Если говорить более подробно, то диск является блокирующим устройством , что означает, что доступ к его содержимому разрешен только для чтения и записи фрагментов хорошо определенных размеров, которые по историческим причинам обычно составляют 512 байт.

Итак, как работают функции, которые позволяют получить доступ к одному char за один раз (рассмотрим, что char в C является наименьшей единицей данных, и на некоторых системах это может быть отличается от 8 бит, то есть 12 или 16 бит)?

Стандартная библиотека C и почти все файловые функции ОС используют механизм буферизации, позволяющий получить доступ к одному файлу char. Система считывает фрагмент данных с диска и передает вам один байт из фрагмента, и так далее до последнего char фрагмента. При следующем запросе пользователя на char функция считывает следующий фрагмент файла с диска, буферизует его внутри и предоставляет пользователю самый первый char из только что прочитанной записи данные.

Этот процесс продолжается до достижения конца файла.

Тот же процесс, но в обратном порядке, выполняется при записи данных на диск a char одновременно. Каждый char буферизуется, и когда размер куска достигнут, он сбрасывается на физический диск.

Чтобы решить вашу проблему, вы должны написать свой собственный набор буферных функций, которые будут читать char одновременно из файла и выводить один бит за раз для каждого запроса. При полной разрядности из char exausted функция прочитает другой символ и начнет снова.

Это небольшой пример такого набора функций:

#include <stdio.h>
#include <limits.h>

/*
 *  Bit FILE pointer structure
 */
typedef struct
{
    FILE *fp;           //Disk file pointer
    int   ReadChar;     //Current char read from stream
    int   BitCounter;   //counter of the current bit
} BITFILE;

/*
 * Function to open a file for bit reading
 */
BITFILE *bfopen(const char *filename)
{
    FILE *fp = fopen(filename, "rb");
    if (!fp)    //Error opening file
        return NULL;

    BITFILE *bf = malloc(sizeof(BITFILE));
    if (!bf)    //No memory
    {
        fclose(fp); //Close file
        return NULL;
    }

    bf->fp         = fp;        //Save File pointer
    bf->ReadChar   = getc(fp);  //Read in first char
    bf->BitCounter = 0;         //First bit

    return bf;
}

/*
 * Function to close (release) a bit file
 */
void bfclose(BITFILE *bf)
{
    if (!bf)    //Bad descriptor
        // Do some error signaling
        return;

    fclose(bf->fp); //Close file
    free(bf);       //release memory
}

/*
 * Function to read a single bit
 */
int fgetbit(BITFILE *bf)
{
    if (!bf)    //Bad descriptor
        // Do some error signaling
        return;

    if (bf->BitCounter >= CHAR_BIT)     //No more bits to read on this machine
    {
        bf->ReadChar   = getc(bf->fp);  //Read in another char
        bf->BitCounter = 0;             //Reset counter
    }

    if (EOF == bf->ReadChar)        //If end of file reached return EOF
        return EOF;

    //Note that to avoid sign complications in bit working
    // we cast the value to unsigned
    int bit      = ((unsigned)bf->ReadChar) & 1;    //Get the LSB that we will return
    bf->ReadChar = ((unsigned)bf->ReadChar) >> 1;   //Advance bits shifting

    bf->BitCounter++;   //Update counter

    return bit;
}

int main(int argc, char *argv[])
{
    BITFILE *bf = bfopen("test.txt");
    if (!bf)
    {
        printf("Error can't open file \"%s\"\n", "test.txt");
        return 1;
    }

    for (int cnt=1; ; cnt++)
    {
        int bit = fgetbit(bf);

        if (EOF == bit)
            break;

        printf ("%3d) bit %d\n", cnt, bit);
    }

    bfclose(bf);

    return 0;
}