2015-04-20 3 views
0

У меня есть .dat-файл, который нужно читать и печатать записи для людей , которые имеют атрибуты, указанные в качестве аргументов командной строки. Формат файла выглядит следующим образом. Записи для каждого человека начинается с беззнаковым 32-битным целым, которое содержит различную информацию о человеке:Чтение данных из двоичного файла .dat

Биты

0-4: длина первого имени (ключ = первом)

5-9 : длина отчества (ключ = средний)

10-14: длина фамилии (ключ = последний)

15-21: возраст (ключ = возраст)

22 : Пол (0 = мужчина, 1 = женский) (ключ = пол)

23-28: состояние (от 0 до 49 в алфавитном порядке) (ключ = состояние)

29: в настоящее время в браке (0 = ложь , 1 = истина) (ключ = женатый)

30: занятые полный рабочий день (используется 0 = ложь, 1 = истина) (ключ =)

31: учился в колледже (0 = ложь, 1 = истина) (key = college)

Я думаю, что я предполагаю сначала прочитать все 32-битные (4 байта), а затем читать по биту из 32-битного целого числа. Я новичок в fread и fseek, поэтому я действительно не знаю, нахожусь ли я на правильном пути, любая помощь будет оценена. Вот мои коды до сих пор.

int main(int argc, char *argv[]) { 

    char *buf; 
    long lSize; 
    size_t result; 

    FILE *fp; 
    fp = fopen("/u1/junk/people.dat","r"); 
    if(fp == NULL) { 
    printf("Error: can't open file to read\n"); 
    return -1; 
    } 
    else { 
    printf("File people.dat opened successfully to read\n"); 
    } 


    //obtian file size 
    fseek(fp, 0, SEEK_END); 
    lSize = ftell(fp); 
    rewind(fp); 

    //allocate memory to contain the whole file 
    buf = (char*) malloc (sizeof(char)*lSize); 

    while (!feof(fp)) { 
    fread(buf, 4, 1, fp); 
    fseek(fp, i, SEEK_CUR); 
    fread(buf, 32, 1, fp); 
    printf("%s\n", buf); 
    i+=32; 
    } 

    fclose(fp); 
    return 0; 
} 
+2

Два основных советов: Не отвергни возвращаемое значение 'таНос()' в C, не используйте 'feof()' для обнаружения конца файла, как это. – unwind

+0

Я думаю, вы должны придумать структуру с битовыми полями и прочитать всю информацию за один раз. –

+0

@ facebook-100001358991487 Я любезно не согласен, потому что это не переносная реализация, хотя OP не упомянула, нужна ли им переносимость. Я бы предпочел видеть, что OP заполняет структуру поле за полем. – siliconwafer

ответ

1
#include <stdio.h> 

// define first 32 bits of record 
struct personRecord 
{ 
    unsigned first :5; 
    unsigned middle :5; 
    unsigned last  :5; 
    unsigned age  :7; 
    unsigned sex  :1; 
    unsigned state :6; 
    unsigned married :1; 
    unsigned employed :1; 
    unsigned college :1; 
}; 

// prototypes 
void processRecord(FILE* fp, char* buf); 


int main(int argc, char *argv[]) 
{ 

    struct personRecord key; 

    FILE *fp; 
    fp = fopen("/u1/junk/people.dat","r"); 
    if(fp == NULL) 
    { 
     printf("Error: can't open file to read\n"); 
     return -1; 
    } 

    // implied else, fopen successful 

    printf("File people.dat opened successfully to read\n"); 



    while (1 == fread(&key, 4, 1, fp)) 
    { 
     processRecord(fp, key); 
    } 

    fclose(fp); 
    return 0; 
} // end function: main 



void processRecord(FILE* fp, personRecord key) 
{ 
     int result; 
     int bufFirst[key.first] = {'\0'}; 
     ... 

     // use lengths to determine how much more bytes to read for each field 
     result = fread(bufFirst, key.first, 1, fp); 
     if (result == key.first) 
     { // then successful acquire first name 
      ... 
     } 
     ... 
     // first, middle, last, 

     // use lookup table to get state name from state field 
     char * pState = alphabeticalState[key.state]; 

     // do something with the extracted info 
     ... 
} // end function: processRecord 


const char * alphabeticalStates[] = 
{ 
    "alabama"; 
    ... 
    "washington"; 
    "wisconsin"; 
}; 
+0

, если вы хотите, чтобы поля сначала, посередине, последним являлись строками, затем каждый массив должен быть максимальной длиной имени + 1 и использовать fgets, а не fread, чтобы ввести значение – user3629249

1

Это непроверено, но, надеюсь, дает вам представление о технике «маска и смена». Вы можете прочитать больше о нем: What are bitwise shift (bit-shift) operators and how do they work? и Bitfield manipulation in C

Допустим, вы читаете беззнаковое 32-разрядное целое число:

unsigned long myint; 
fread(&myint, sizeof(myint), 1, fid); 

Теперь, сдвиг и маску, чтобы вытащить значения из.

// bits 0-4 (5 bits) 
unsigned long firstNameLength = myint & 0xF1; 

// bit 31 
unsigned long attendedCollege = (myint & 0x0000000E) << 31; 
+0

Эта строка: «unsigned long IncludedCollege = (myint & 0x0000000E) << 31;» неверно. 1) посещаемый колледж - только 1 бит, в то время как «E» - 3 бита. 2) бит (если сдвинут) необходимо сдвинуть вправо на 31 бит, а не налево. Предложить: 'unsigned long takenCollege = (myint & 0x80000000) >> 31;' BTW: нет гарантии, что «long int» равен 4 байтам, единственная гарантия - это 4 Мбайт. Для наших целей было бы намного проще объявить массив из 4 символов и манипулировать содержимым. – user3629249