【问题标题】:what is the EOF of binary file?什么是二进制文件的EOF?
【发布时间】:2015-01-20 22:49:33
【问题描述】:

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

结构:

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

【问题讨论】:

  • 也许您输入的文件包含一些您不期望的额外数据?一个额外的字节就足以打破逻辑。
  • fread有一个返回值是有原因的。
  • 也许文件最后包含一个 NULL 字符?你怎么把字符串写到文件中?

标签: c linked-list binaryfiles


【解决方案1】:

调用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 的元素数。

【讨论】:

  • 是否可以用 fseek 和 ftell 将文件大小保存在计数器中,然后在 ftell 到达计数器时放置断点?
  • @SashaG 这当然也是可能的。但是,检查每个fread 如果错误发生在文件读取过程中的“飞行中”,则可以更好地发现错误。
【解决方案2】:

检查fread() 而不是foef(),Stack Overflow 上有很多关于此的答案,feof() 在设置 EOF 指示器时返回 true,fread() 将在读取文件末尾时设置它。

fread() 将在到达文件末尾时返回 0 或小于请求的字节数,但是您的程序需要一个额外的循环,其中 fread() 尝试读取文件末尾,并且它将设置EOF 指标。

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

【讨论】:

    【解决方案3】:

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

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

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

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

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

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

    【讨论】:

      【解决方案4】:
      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 ) 
      ... 
      

      【讨论】:

        猜你喜欢
        • 2013-05-16
        • 2020-09-25
        • 1970-01-01
        • 2014-10-17
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多