C как читать в одном бите из файла - PullRequest
0 голосов
/ 08 мая 2018

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

"привет"

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

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

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

Ответы [ 3 ]

0 голосов
/ 08 мая 2018

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

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

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

bool getBit(unsigned char byte, int position) // position can be 0-7
{
    return (byte >> position) & 0x1;
}
0 голосов
/ 08 мая 2018

Как все говорили, в C. нет доступных функций доступа к битам.

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

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

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

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

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

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

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

#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;
}
0 голосов
/ 08 мая 2018

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

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

#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
}
...