Sasha G
Sasha G

Reputation: 33

what is the EOF of binary file?

My program needs to read from a binary file to a linked list, this function doing it well and allocating the right memory for it but for some reason it doing another loop before it breaks. tried looking for a good solution for it with no luck, and the last struct in the linked list getting junk.

The struct:

typedef struct
{
    char id[10];
    char * first_name;
    char * last_name;
    int age;
    char gender;
    char * username;
    char * password;
    char * description;
    int hobbies[4];
    struct Person * next_client;
}Person;

here is some code:

Person * input_from_file(Person * member)
{
int str_size;
Person * clients_start = NULL;
FILE * filePointerRead;

filePointerRead = fopen("input.bin", "rb");

if (filePointerRead != NULL){
    while (1){

        member = NULL;
        member = (Person*)malloc(sizeof(Person));

        fread(&member->id, sizeof(char), ID_DIGITS + 1, filePointerRead);

        fread(&str_size, sizeof(int), 1, filePointerRead);
        member->first_name = (char*)malloc(str_size*sizeof(char));
        fread(member->first_name, sizeof(char), str_size, filePointerRead);

        //more reading from file

        member->next_client = NULL;
        clients_start = receive_clients_info(clients_start, member);  //function to put the received struct from file to end of the linked list

        if (feof(filePointerRead))
            break;
    }
    fclose(filePointerRead);
}
return clients_start;
}

Upvotes: 1

Views: 6661

Answers (4)

user3629249
user3629249

Reputation: 16540

any easy way to accomplish the task is:

calculating the total length of each complete record in the file
 (from your code, I assume all records are the same length) 
fopen( ..inputfile.. )
if fopen not successful, 
then
    perror()
    exit( EXIT_FAILURE );
endif

// implied else, fopen successful

while(completelength == fread( the complete length into a local buffer))
{ 
    ...extract each field from local buffer into struct...
    ...place struct into linked list... 
}  

//when get here, reading/building linked list is done 
fclose( inputfile ) 
... 

Upvotes: 0

OfNothing
OfNothing

Reputation: 600

The issue you are having is that feof() does not return true until the EOF flag of a file is set, and the EOF flag of a file is not set until an attempt to read the file fails because there is no data left in the file to read.

Here is an example: imagine that the file has 1 byte in it and you have a loop that reads the file one byte at a time.

The first time through the loop, one byte is read and given back to the program. If the program tests feof() it will still return FALSE because reading the file succeeded.

The second time through the loop, all of the bytes from the file have already been read so 0 byes are read and returned to the program, at this time, the EOF flag is set because reading the file failed due to reaching the end. At this point feof() will then return TRUE.

In my example, you went through the loop twice even though there was only one byte in the file. The same is happening to your code.

To solve the problem, always check the result of the fread() call. It returns the number of items (not bytes) read. By the way, fread() will always read an entire item and never a partial item. If fread() returns fewer items than you expect, break out of the loop. Usually, you will break out of the loop because you have reached the end of the file, but there is a chance that there was some other error -- maybe somebody pulled the power cord to an external hard drive. If you want to see why fread() did not read anything, you can then use feof() or ferror().

Upvotes: 1

Sergey Kalinichenko
Sergey Kalinichenko

Reputation: 726809

The problem with calling feof is that it wouldn't return you a "true" unless you have attempted a read when you are at the EOF. In other words, if your file has exactly 100 bytes, and you have successfully attempted reading exactly 100 bytes, feof would return "false" until you try reading at least one more byte.

That is the reason why you should avoid feof in favor of checking the return value of fread, which tells you how many bytes has been read from file:

if (fread(&member->id, sizeof(char), ID_DIGITS + 1, filePointerRead) != ID_DIGITS + 1) {
    // The code above knows that sizeof(char) is always 1.
    // For other data types you need to compute the actual size
    // by multiplying sizeof(T) by the number of items that you read.
    break;
}

Do the same in all places where you call fread.

Comparison with != works because fread always returns the exact size that you pass when it can complete the request:

Upon successful completion, fread() shall return the number of elements successfully read which is less than nitems only if a read error or end-of-file is encountered.

Upvotes: 4

Iharob Al Asimi
Iharob Al Asimi

Reputation: 53016

Check fread() instead of foef(), there are many answers on Stack Overflow about that, feof() returns true when the EOF indicator is set, fread() will set it when reading past the end of the file.

fread() will return 0 or less than the requested bytes when the end of the file is reached, but your program requires one extra loop in which fread() tries to read past the end of the file, and it will set the EOF indicator.

See this “while( !feof( file ) )” is always wrong

Upvotes: 2

Related Questions