accraze
accraze

Reputation: 1552

Reading a File into an array of Structures in C

still really new to C but starting to get the hang of it....

My program is supposed to create/write a file and store information from an array of structures. That part is fine. What im having trouble with is reading from that file back into an empty array of structures....

here's my structs:

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

#define MAX 100

struct Video { 
char name[1024];                //name
int ranking;                // Number of viewer hits
char url[1024];             // YouTube URL
};

struct Video Collection[MAX];

here's my load method which reads from my file back into my array of structures:

void load()
{
FILE *fileName;
fileName = fopen("ranking.dbm", "rb");
if (fileName != NULL){
    fread (Collection,1,1,fileName);
}
else {
    printf("ERROR");
}   

}

also here is my write method:

void save()
{
FILE * pFile;
pFile = fopen ( "Ranking.dbm" , "wb" );
fwrite (Collection, 1 , sizeof(Collection), pFile );
fclose (pFile); 
}

however when i print out my array collection after loading.... its empty... even though i can see my file in the project folder and open it and verify that the data is in there....

am i correct in thinking that i dont need a buffer since i don't need to do any processing on it before using it?

also since i've already statically allocated space for memory.... am i correct in thinking that i can just read directly into the array?

here is my print code:

void printall()
{
int i; 

printf("\nCollections: \n"); 

for(i = 0; i < tail; i++)
{
    printf("\nVideo Name: %s", Collection[i].name);
    printf("\nRanking (Hits): %d", Collection[i].ranking);
    printf("\nURL: %s", Collection[i].url);
    printf("\n");
}
}

Upvotes: 1

Views: 17199

Answers (3)

Mike
Mike

Reputation: 49493

I'm seeing a few issues here.. first how you read the file:

fread (Collection,1,1,fileName); 

This will read into collection 1 byte from fileName into Collection
You should check the return status of fread(), when it's successful it tells you the total number of bytes to be read. (parameter 2 * parameter 3, or 1*1 in your case).

When I modify your read code like this:

fread(Collection, sizeof(struct Video), 1, fileName);

It does successfully read from the file... however you have a different problem now. Let's say your file contained this:

something 5 http://something.com
nothing 3 http://nothing.com

So (I think) that's the format for your file, a name (ASCII), a ranking (int), and URL (ASCII). Now let's say your main() function looked like this:

int main ()
{
    load();
    printall();
    return 0;
}

What you'd get back on stdout would be something like:

Collections:

Video Name: something 6 http://something.com
nothing 3 http://nothing.com
Ranking (Hits): 0
URL: 

The reason is because you declared your array with static (and very large) elements. The fread() will try to read in the sizeof(struct Video) which is 1024+4+1024 bytes, so unless every one of your lines is the exact size (1024 chars for name and url) then you're going to get what looks like messed up or empty data.

I would suggest reading until you hit a space instead and storing each value in the correct element instead of trying to read out the full file into an array.

EDIT:
If you want to populate your array like:

fread(myarray, sizeofstruct, numberofstructs, file);

You have to guarantee the data length. In your example you'd have to say "name is however many characters, + blank spaces = 1024" and same for URL. That seems to be a horrible space waster. The better bet is to populate your array one element at a time:

for(0 to last_element){
  set myarray.name = data until first space
  set myarray.ranking = (int)data until second space
  set myarray.url = data until newline
}

You can use fscanf() to read until a whitespace. Frankly if you're going to populate one element at a time I'd just use character pointers for name and url and dynamically assign memory so you don't have huge wasted arrays.

Upvotes: 2

nneonneo
nneonneo

Reputation: 179717

fread is in fact designed to read arrays of structures from a file, but you have to use it correctly.

fread's four parameters are as follows:

void * ptr, size_t size, size_t count, FILE * stream

The first parameter is where to put the data (in your case, Collection). The second parameter is the size of each array element: in your case, you want to put sizeof(struct Video). The third parameter is the number of elements you want to read, in your case, MAX. The fourth parameter is the file to read from.

If you want to read into an array like struct Video Collection[MAX], you would then use fread(Collection, sizeof(struct Video), MAX, file). fread will return the total number of elements read, which will be ≤ MAX.

Upvotes: 4

Sergey L.
Sergey L.

Reputation: 22562

First I have to assume you meant struct Video Collection[MAX];else your upper part is invalid C.

Second: you are reading 1 byte into Collection.

Try fread(Collection, sizeof(struct Video), MAX, fileName);

This will read up to MAX times chunks of sizeof(struct Video)bytes into Collection.

Upvotes: 1

Related Questions