如何将二进制文件读取到 C 中的结构

How to read a binary file to a structure in C

我有一个名为 product 的结构,我正在尝试从二进制文件中读取它来填充此函数:

void reading(FILE *fp){

  Product *obuff = malloc(sizeof(Product));
  fread(obuff->code, sizeof(obuff->code), 1, fp);
  fread(obuff->name, sizeof(obuff->name), 1, fp);
  fread(obuff->quantity, sizeof(obuff->quantity), 1, fp);
  fread(obuff->price, sizeof(obuff->price), 1, fp);   

  printf("%s %s %d %.2f\n", obuff.code, obuff.name, obuff.quantity, obuff.price);
}

当我尝试编译时出现错误,提示由于数据类型错误我无法传递参数。有没有办法从二进制文件中读取结构,或者我只是在这里做错了什么?

结构:

#pragma pack(2)
struct product {
   char code[15];
   char name[50];
   short int quantity;
   double price;
};
#pragma pack()

typedef struct product Product;

您必须传递 指针 才能让 fread() 读取数据。

void reading(FILE *fp){

  Product *obuff = malloc(sizeof(Product));
  fread(&obuff->code, sizeof(obuff->code), 1, fp);
  fread(&obuff->name, sizeof(obuff->name), 1, fp);
  fread(&obuff->quantity, sizeof(obuff->quantity), 1, fp);
  fread(&obuff->price, sizeof(obuff->price), 1, fp);

  printf("%s %s %d %.2f\n", obuff->code, obuff->name, obuff->quantity, obuff->price);
  free(obuff); /* free whatever you allocated after finished using them */
}

http://www.tutorialspoint.com/c_standard_library/c_function_fread.htm 所述,您必须将指针传递给 fread:

 size_t fread(void *ptr, size_t size, size_t nmemb, FILE *stream)

fread 的第一个参数不是指针;

 fread(obuff->code ...

Please pay attention to the fread()'s definition, The first argumnet need to be one pointer.; And another litter mistake is we need to make use of "->" to get the element in printf() Function.

Below are my modification:

void reading(FILE *fp){

  Product *obuff = malloc(sizeof(Product));
  fread(obuff->code, sizeof(obuff->code), 1, fp);
  fread(obuff->name, sizeof(obuff->name), 1, fp);
  fread(&obuff->quantity, sizeof(obuff->quantity), 1, fp);
  fread(&obuff->price, sizeof(obuff->price), 1, fp);   

  printf("%s %s %d %.2f\n", obuff->code, obuff->name, obuff->quantity, obuff->price);
}

这段代码有几个问题。其中一些会阻止编译,而另一些可能会导致不稳定的行为。由于不稳定的行为是您可能不会注意到的,我将首先介绍它。


在尝试使用它之前,您应该始终检查 malloc 的 return 值。 例如:

Product *obuff = malloc(sizeof *obuff);
if (obuff == NULL) {
    /* obuff can't be used because allocation failed */
    return;
}

在相关说明中,正如 MikeCAT 所建议的那样,当您完成 malloc',realloc' 或 calloc'...

在另一个相关说明中,您也不应使用值 obuff->codenamequalityprice,除非 return 值为 fread 表示成功。


fread(&obuff->code, sizeof(obuff->code), 1, fp);
fread(&obuff->name, sizeof(obuff->name), 1, fp);

这将编译,但是您不需要和号 (&),实际上不应该在这里使用它们。表达式 obuff->code&obuff->code 都指向同一个地方(因为 obuff->code 是一个数组)但是它们指向的对象类型不同; obuff->code 指向数组的第一个字节,而 &obuff->code 指向整个数组。


fread(&obuff->quantity, sizeof(obuff->quantity), 1, fp);
fread(&obuff->price, sizeof(obuff->price), 1, fp);  

这将编译,并向您说明 do 需要此处的 & 符号,但是话虽如此 short intdouble 可能在不同的系统上有不同的表示。 您需要通过 序列化 这些字段在文件中形成一致的表示。序列化是一个冗长的主题,更适合作为软件设计书籍的一个章节,因此为了简洁起见,我将继续讨论,除非在此提出有关该主题的进一步具体问题。


#pragma pack(2)

这是不可移植的,在您提供的代码中没有真正需要它。


printf("%s %s %d %.2f\n", obuff.code, obuff.name, obuff.quantity, obuff.price);

预计%s对应的是一个指向字符串的指针;字符串是在第一个'[=34=]'字符处结束的字符序列.但是,您的代码没有明确分配任何 '[=34=]' 字符,因此我们不能保证 obuff.codeobuff.name 字符串。如果不是,则行为未定义(或 不稳定 ,正如我喜欢描述的那样)。也许您打算分别使用 %15s%50s 来表示它们 可能 是字符串,但如果不是,则有最大长度?

这也是你编译错误的来源。请注意,在之前的代码片段中,您如何引用 obuff->codeobuff->name,而在此片段中,您如何引用 obuff.code、等? . 运算符访问结构的字段,而 -> 运算符访问指向结构的字段...也许您打算在这里使用 -> 运算符?