2015-01-20 149 views
0

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

的结构:

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

也许你输入的文件包含一些额外的数据,你不期待?一个额外的字节足以打破逻辑。 – 2015-01-20 22:52:00

+1

'fread'有一个返回值的原因。 – 2015-01-20 22:52:32

+0

[如何使用EOF运行C中的文本文件?]的可能重复(http://stackoverflow.com/questions/1835986/how-to-use-eof-to-run-through-a-text- file-in-c) – gsamaras 2015-01-20 22:52:59

回答

2

与调用feof的问题是,它不会回你一个“真正的”,除非你试图读时你在EOF。换句话说,如果您的文件刚好有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只如果遇到读取错误或文件结束。

+0

是否可以像fseek和ftell那样在柜台上保存文件的大小,然后在ftell达到计数器时放置断点? – 2015-01-20 23:39:14

+0

@SashaG这当然也是可能的。但是,检查每个“fread”,如果在文件读取过程中发生“中途飞行”,就会更容易发现错误。 – dasblinkenlight 2015-01-21 00:45:20

2

检查的fread()代替foef(),也有对堆栈溢出有关,feof()返回true多的答案时,EOF指标设置,fread()将在读取文件结尾时设置它。

fread()将返回比当到达文件的末尾,但你的程序需要一个额外的循环,其中fread()试图读到文件的末尾,它将设置EOF指标所要求的字节0以下。

看到这个“while(!feof(file))” is always wrong

1

您遇到的问题是,直到文件的EOF标志被设置,feof()才返回true,并且文件的EOF标志没有被设置,直到尝试读取文件失败,因为在那里没有数据留在文件中读取。

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

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

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

在我的例子中,即使文件中只有一个字节,你也经历了两次循环。你的代码也一样。

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

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