#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 важен, поскольку он позволяет избежать выравнивания данных компилятором в структуре, поэтому он может точно соответствовать вашему формату на диске!