Jasmine
Jasmine

Reputation: 323

Reading bytes of a file into a structure

How would I go about reading a binary file and assigning their values to a structure? Each structure with its content will be written to a csv file.

I have this data file, it's a list of struct product entries.

Here is the Product structure in an h file:

struct product {
    char code[15];
    char name[50];
    short int quantity;
    double price;
}

typedef struct product *Product;

And here is how I'm trying to read each line into the Product structure and writing it to the csv file:

File *fp;
File *outFile;
fp = fopen("products.dat", "rb");
outFile = fopen("allproducts.csv", "w");
Product p;

while (fread(p, sizeof(Product), 1, fp) == 1) {
    fwrite(p->code, sizeof(p->code), 1, outFile);
}

I don't think I'm reading the file correctly because when I try writing to the file, all I get are the question marks in a box in the csv file.

Upvotes: 1

Views: 176

Answers (3)

chqrlie
chqrlie

Reputation: 145307

Hiding pointers behind typedefs is error prone and leads to confusing code.

  • p is defined as a pointer to a struct product, but is not initialized: passing its value to fread as the destination invokes undefined behavior.

  • sizeof(Product) is the size of the pointer, not the size of the structure.

Do not define Product as a pointer, make it a typedef for the structure if you can, or do not use the typedef if you cannot:

struct product {
    char code[15];
    char name[50];
    short int quantity;
    double price;
};

typedef struct product Product;

Adjust the code and write the string to the csv file, not the complete array of chars:

File *fp;
File *outFile;
fp = fopen("products.dat", "rb");
outFile = fopen("allproducts.csv", "w");
struct product prod;

while (fread(&prod, sizeof(prod), 1, fp) == 1) {
    fprintf(outFile, "%s\n", prod.code);
}

Note that this will be incorrect if the product code contains embedded spaces, ,, " or newline characters.

Upvotes: 0

Jay
Jay

Reputation: 24905

I think your below code needs to be modified.

Your Original Code:

File *fp;
File *outFile;
fp = fopen("products.dat", "rb");
outFile = fopen("allproducts.csv", "w");
Product p;

while (fread(p, sizeof(Product), 1, fp) == 1) {
    fwrite(p->code, sizeof(p->code), 1, outFile);
}

Modified Code:

File *fp;
File *outFile;
fp = fopen("products.dat", "rb");
outFile = fopen("allproducts.csv", "w");
Product p = malloc(sizeof(struct product));

while (fread(p, sizeof(struct product), 1, fp) == 1) {
    fwrite(p->code, sizeof(p->code), 1, outFile);
}

Problems are:

  1. p is a pointer to struct as it is of type Product which is a pointer to struct, you need to allocate memory for it before you can use it
  2. In fread you are passing sizeof(Product) which essentially passes the size of the pointer, whereas you want to read the sizeof the structure product.

The other problems which I haven't corrected is checking the return values of fopen,malloc etc which I leave it to you. : )

Upvotes: 0

deamentiaemundi
deamentiaemundi

Reputation: 5525

If the writer of the data file does not take care for the size of the struct it writes, the reader has trouble to make sense of it. I played around with it a bit and found out that a small adjustment is needed to get the proper result on my machine and OS.

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

#define ADJUSTMENT 4

struct product {
  char code[15];
  char name[50];
  short int quantity;
  double price;
};

int main(void)
{
  FILE *fp;
  //FILE *outFile;
  struct product p;

  fp = fopen("products.dat", "rb");
  if (fp == NULL) {
    fprintf(stderr, "fopen failed\n");
    exit(EXIT_FAILURE);
  }
  //outFile = fopen("allproducts.csv", "w");

  while (fread(&p, sizeof(p) - ADJUSTMENT, 1, fp) == 1) {
    printf("CODE: %s\n", p.code);
  }
  exit(EXIT_SUCCESS);
}

It is a well known problem with such simple attempts for writing binary data, it is just not portable and I'm pretty sure that the value of my adjustment does not fit for you. You need to find a method to make it portable.

Upvotes: 1

Related Questions