什么是二进制文件的EOF?

时间:2015-01-20 22:49:34

标签: c linked-list binaryfiles

我的程序需要从二进制文件读取到链接列表,这个函数做得很好并为它分配正确的内存但由于某种原因它在它中断之前做了另一个循环。试图找到一个好的解决方案,没有运气,链接列表中的最后一个结构变得垃圾。

结构:

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;

这里有一些代码:

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;
}

4 个答案:

答案 0 :(得分:4)

调用feof的问题在于,除非您在EOF时尝试读取,否则它不会返回“true”。换句话说,如果您的文件只有100个字节,并且您已成功尝试读取100个字节,feof将返回“false”,直到您尝试至少再读取一个字节为止。

这就是你应该避免feof支持检查fread的返回值的原因,它会告诉你从文件中读取了多少字节:

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;
}

在您致电fread的所有地方都这样做。

!=的比较有效,因为fread始终会返回完成请求时传递的确切大小:

  

成功完成后,fread()将仅在遇到读取错误或文件结束时返回成功读取的元素数,该元素数小于nitems

答案 1 :(得分:2)

检查fread()而不是foef(),Stack Overflow上有很多答案,当设置EOF指标时feof()返回true,fread()将设置它阅读文件的末尾。

当达到文件末尾时,

fread()将返回0或小于请求的字节数,但是您的程序需要一个额外的循环,其中fread()尝试读取结束该文件,它将设置EOF指示符。

请参阅此“while( !feof( file ) )” is always wrong

答案 2 :(得分:1)

您遇到的问题是,在设置文件的EOF标志之前,feof()不会返回true,并且在尝试读取文件失败因为没有数据之前,文件的EOF标志未设置留在文件中阅读。

这是一个例子:假设文件中有1个字节,并且你有一个循环,一次读取一个字节的文件。

第一次循环时,读取一个字节并返回给程序。如果程序测试feof(),它仍将返回FALSE,因为读取文件成功。

第二次循环时,文件中的所有字节都已被读取,因此读取0个字节并返回给程序,此时,EOF标志被设置,因为读取文件失败是因为到达了结束。此时,feof()将返回TRUE。

在我的示例中,即使文件中只有一个字节,您也会经历两次循环。您的代码也会发生同样的情况。

要解决此问题,请始终检查fread()调用的结果。它返回读取的项目数(不是字节数)。顺便说一下,fread()将始终读取整个项目而从不读取部分项目。如果fread()返回的项目少于预期,则跳出循环。通常,您将跳出循环,因为您已到达文件的末尾,但有可能存在其他错误 - 也许有人将电源线拉到外部硬盘驱动器。如果你想知道为什么fread()没有读任何东西,你可以使用feof()或ferror()。

答案 3 :(得分:0)

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 ) 
...