1

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");
}
}
7
  • 1
    Could you double-check your source? Between the Video struct and the declaration of Collection, I think something is missing.. Commented Sep 29, 2012 at 18:21
  • Do you want the file to be in binary or in textual form? Do you care about portability of the data file on different architectures? Commented Sep 29, 2012 at 18:23
  • I think you want to define: struct Video Collection[MAX]; Commented Sep 29, 2012 at 18:27
  • 1
    P.S. Don't call the FILE * object fileName, or it will be very confusing (since it is not a file name). Commented Sep 29, 2012 at 18:28
  • yep sorry it is supposed to be struct Video Collection[MAX]. edited the above post Commented Sep 29, 2012 at 18:31

3 Answers 3

4

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.

Sign up to request clarification or add additional context in comments.

4 Comments

went ahead and tried this....however it still is printing out an empty array. i added my write method code above.... it is writing data to a file but im not sure if its correct.
How are you printing the array?
added my print code above... it works when i print the array before writing/reading tho...
Note that fread returns the number of elements read, so you should set tail = fread(...) in order to print out the right number of elements.
2

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.

2 Comments

thanks for the detailed response!is there a way to structure my save() method in order to write to the file thats in an easier to read-in format? for example something like fwrite (Collection, sizeof(struct YouTubeVideo) , MAX , pFile ); ?
@SunHypnotic - It's more about the fact that you're dealing with unstructured sizes (name & url) then how you're storing it. See my edit and let me know if that answered your question.
1

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.

2 Comments

so in my write method.... should i also be using sizeof(struct Video) instead of sizeof(Collection) ?
Ideally yes. The reason is that if your write buffer is not large enough to hold your whole collection at once the write will fail, so writing in struct Video chunks is a safer choice. Generally whenever using read/write you always have to double check whether your whole buffer was actually read/written.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.