• Welcome to Overclockers Forums! Join us to reply in threads, receive reduced ads, and to customize your site experience!

Writing/reading a binary file in C

Overclockers is supported by our readers. When you click a link to make a purchase, we may earn a commission. Learn More.

CGfreak102

Registered
Joined
May 20, 2012
Hey everyone, have a programming assignment for my system programming class and having some troubles with it right now. First off we had to make a struct to hold data about mp3 songs, and created a text file (outside of the program in notepad) with details. I then open that file and read in the information. That works just fine.

My issue lies with writing that struct to binary, and then reading it from that file to fill a new array. Here is my code so far;

Code:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

typedef struct mp3
{
  char artist[1024];
  char title[1024];
  char size[1024];
  char bit_rate[1024];
} mp3;

//prototypes
void read_file(FILE* fin, mp3* arr[]);
int create_binary(FILE* fout, mp3* arr[]);
void free_elements(mp3* arr[]);
void read_binary(FILE* fin, int wrote);

int main()
{
  int i;
  int wrote;
  mp3* arr[1024];
  for(i = 0; i < 1024; ++i)
  {
    arr[i] = (mp3*)malloc(sizeof(mp3));
  }
  FILE* fin = fopen("mp3.txt", "r");
  FILE* fout = fopen("mp3.bin", "wb+");
  if(fin == NULL)
  {
    printf("\nmp3.txt could not be opened");
    exit(1);
  }
  if(fout == NULL)
  {
    printf("\nmp3.bin could not be opened/crated");
    exit(1);
  }
  read_file(fin, arr);
  wrote = create_binary(fout, arr);
  free_elements(arr);
  read_binary(fin, wrote);
  //fclose(fin);
  //fclose(fout);
  return 0;
}

void read_file(FILE* fin, mp3* arr[])
{
  int j = 0;
  char line[1024];
  char temp[1024];
  char *data[3];
  while(( fgets(line, sizeof(line), fin)) != NULL)
  {
    printf("\n");
    strcpy(temp, line);
    //printf("%s", temp);
    data[0] = strtok(temp, "|");
    //printf("%s", data[0]);
    data[1] = strtok(NULL, "|");
    data[2] = strtok(NULL, "|");
    data[3] = strtok(NULL, "|");
    //printf("%s", data[2]);
    //memcpy(arr[j]->artist, data[0], sizeof(data[0]));
    strcpy(arr[j]->artist, data[0]);
    strcpy(arr[j]->title, data[1]);
    strcpy(arr[j]->size, data[2]);
    strcpy(arr[j]->bit_rate, data[3]);
    printf("%s", arr[j]->artist);
    ++j;
  }
}

int create_binary(FILE* fout, mp3* arr[])
{
  int i;
  int wrote = 0;
  fclose(fout);
  fout = fopen("mp3.bin", "wb");
  if(fout == NULL)
  {
    printf("\nmp3.bin count not be opened.");
    exit(1);
  }
  for(i = 0; i < 1024; ++i)
  {
    if(arr[i] != NULL)
    {
      ++wrote;
    }
  }
  fwrite(arr, sizeof(mp3), wrote, fout);
  printf("%d", wrote);
  fclose(fout);
  return wrote;
}

void free_elements(mp3* arr[])
{
  int i;
  //printf("%d", sizeof(mp3));
  for(i = 0; i < 1024; ++i)
  {
    if(arr[i] != NULL)
    {
      free(arr[i]);
      arr[i] = NULL;
    }
  }
  //printf("%d", sizeof(mp3));
}

void read_binary(FILE* fin, int wrote)
{
  int i;
  mp3* arr[1024];
  for(i = 0; i < 1024; ++i)
  {
    arr[i] = (mp3*)malloc(sizeof(mp3));
  }
  fclose(fin);
  fin = fopen("mp3.bin", "rb");
  if(fin == NULL)
  {
    printf("\nmp3.bin count not be opened.");
    exit(1);
  }
  fread(arr, sizeof(mp3), wrote, fin);
  //for(i = 0; fread(arr[i], sizeof(mp3), 1, fin) == 1; ++i);
  printf("%s", "\n");
  for(i = 0; i < 10; ++i)
  {
    printf("%s", arr[i]->artist);
    printf("%s", " ");
    printf("%s", arr[i]->title);
    printf("%s", " ");
    printf("%s", arr[i]->size);
    printf("%s", " ");
    printf("%s", arr[i]->bit_rate);
    printf("%s", " ");
    printf("%s", "\n");
  }
  fclose(fin);
  //free_elements(arr);
}

The program compiles fine, but when i run it and read back in the binary file the very first data field (artist) gets some random garbage values. Shown in the following output;

Code:
h▒l▒ Mountain Music 5967 160

h▒l▒ Chattahoochee 5782 160

h▒l▒ People are crazy 5564 196

h▒l▒ International Harvester 5508 196

h▒l▒ Pontoon 4929 320

h▒l▒ Out Song 4998 320

h▒l▒ Sweet Home Alabama 9683 160

h▒l▒ I Love This Bar 5146 196

h▒l▒ Good Time 8958 320

h▒l▒ Chicken Fried 7895 196

It gets in the other values just fine not sure why this is happening as this is my first time using fwrite and fread. I asked my TA and he said to try this;
you have 4 arrays of 1024 characters. Fwrite(<your structs>, sizeof(<your struct>),...,...); writes out ALL of the characters, even the ones that don't have a useful value. Then you read all the characters (even the ones that had garbage values) and I think you're getting the weird output. You should try to print only the characters that you use. Don't fwrite the entire struct, fwrite each variable individually. So the suggestion in class is to write the length of the string, then the string itself. If your title is just "title" and artist is just "artist" then your file would look something like
5title6artist
5title6artist

and so on. SO overall my suggestion is to try writing out only the characters you used. You can probably use the strlen function to figure out the length. Be careful though, if you use strlen it only gives you the length of the string minus the null character. If you use strlen, then, you will need to append '\0' to the end of your string when you read it from the binary file

My understanding of that is to put the fwrite in a for loop, and as that incremets check the arr (variable, of struct mp3) at the current value and if it is NOT null to then write that to a file. When i try that, i used a int wrote to see how many variables of the arr are used, and it returns a value of 1024 (size of array). Not sure why that would happen either.

Any pointers at this point would be very helpful.
Thanks
-CGfreak102
 
Pretty sure i figured my issue out, next question; is this following code fine to free the memory of the array?

Code:
void free_elements(mp3* arr[])
{
  int i;
  for(i = 0; i < 1024; ++i)
  {
    if(arr[i] != NULL)
    {
      free(arr[i]);
      arr[i] = NULL;
    }
  }
}
 
Back