Преобразует биты в формат, читаемый человеком

#c #file #pointers #struct #binary

#c #файл #указатели #структура #двоичный

Вопрос:

Я хочу прочитать двоичный файл в структуру

 struct rec
{
    int type;
    long length;
    int data[100];
};
  

Первые 16 бит двоичного файла — это тип, следующие 32 бита — это длина данных, далее идут сами данные. В файле несколько записей, и последняя запись имеет длину 0, соответствующую концу файла.

Я хочу прочитать и распечатать значения каждой записи.

Я нашел способ считывать тип и длину, но я застрял, пытаясь использовать длину для чтения данных. Кроме того, как я могу поместить это в цикл до тех пор, пока длина = 0?

 int main()
{
    FILE *ptr_tofile;
    struct rec some_record;
    ptr_tofile=fopen("Test.bin","rb");

    if (!ptr_tofile)
    {
        printf("Unable to open file!");
        return 1;
    }

    for ( until length = 0)
    {
        fread(amp;some_record, sizeof(int), 1, ptr_tofile);
        printf("%dn",some_record.type);
        fread(amp;some_record, sizeof(int), 2, ptr_tofile);
        printf("%dn",some_record.type);
        getch();
    }
    fclose(ptr_tofile);
    return 0;
}
  

Ответ №1:

Вот альтернативный метод использованию гибкого элемента массива:

 #include <stdlib.h>
#include <stdio.h>
#include <errno.h>

typedef struct file_s {
  int16_t type;
  int32_t length;
  // Assumption: Each record is 16 bits
  // For a record size of 32 bits, use int32_t*
  int16_t* data;
} file_s;

int main() {
  file_s file;
  FILE* f = fopen("file.bin","r");
  if (f == NULL) {
    perror("Error");
    return 1;
  }
  fread(amp;file.type, sizeof(file.type), 1, f);
  fread(amp;file.length, sizeof(file.length), 1, f);
  // Assumption: the length of the data is the number of records
  // If the length is in bytes, you should divide it by the size
  // of a record to obtain the number of records
  file.data = malloc(file.length * sizeof(*file.data));
  // sizeof is a compile-time operator so sizeof(*p) is not a null dereference
  fread(file.data, sizeof(*file.data), file.length, f);
  fclose(f);
  // Process the data
  /* ... */
  free(file.data);
  return 0;
}
  

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

Комментарии:

1. Где здесь происходит зацикливание? Это просто чтение первых трех записей?

2. fread(file.data, sizeof(*file.data), file.length, f); считывает все записи в файле одновременно. Если вы проверите документацию fread , вы можете увидеть, что с помощью этих параметров он считывает file.length количество элементов размером sizeof(*file.data) байт каждый, в общей сложности file.length * sizeof(*file.data) байт. По техническим причинам этот метод быстрее, чем циклический.

3. Ну и что, если я хочу распечатать тип, длину и данные. Как мне это сделать в этом случае?

4. ie. Распечатайте все типы, длину и данные записи.

5. Я предполагаю, что это просто чтение первого типа, длины и данных. Что, если файл имеет: type1, length1, data1, type2, length2, data2, type3, length3, data3 … Как он будет продолжать чтение и печать до тех пор, пока длина не будет равна 0?

Ответ №2:

Вы можете определить гибкий массив в struct, например:

 #pragma pack(push, 1)
typedef struct {
    int16_t type;
    int32_t length;
    int     data[];
} record_t;
#pragma pack(pop)
  

и используйте следующий псевдокод для чтения одной записи.

 record_t *r1;
r1 = calloc(1, sizeof(record_t));
//read the record head to r1, sizeof(record_t)
r1 = realloc(r1, r1->length*sizeof(int) sizeof(record_t));
//read the rest of the record to r1->data, assume it is of type int.
  

Обратите внимание, что #pragma pack важен, поскольку он позволяет избежать выравнивания данных компилятором в структуре, поэтому он может точно соответствовать вашему формату на диске!