Reputation: 323
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
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
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:
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 itfread
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
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