当文件未按预期 100% 填充时,无法使用 C 从二进制文件读取结构

unable to read struct from a binary file using C when file is not 100% filled as expected

我有这个文件,我尝试使用结构从中读取联系人以获得一个简单的通讯录。

typedef struct contact{
    char name[80];
    char surname[80];
    char cellnumber[20];
    float length;
    int contactid;
}contact;

我使用这个函数,我这样调用它所以它读取了 200 次 (const int MAXCONTACT = 200;)。

for(i2=0;i2<MAXCONTACT;i2++)
    person[i2]=load(i2);

这是给定一个ID(变量i)的函数,return是具有相同I的联系人:

contact load(int i){
    struct contact person;
    FILE *data;
    data=fopen("data.bin","rb");
    do{
        fread(&person,sizeof(contact),1,data);
    }while(person.contactid!=i);
    fclose(data);
    return person;
}

这种代码的唯一问题是,当没有 200 个联系人时,该函数将不会 return 一个联系人,因为找不到联系人 ID。

我想到了一些解决方案,但它们相当复杂,我想知道它们是否可以做得更好。

  1. 创建一个像真正的安装程序一样创建文件的安装程序,然后创建 200 个变量为空的未声明联系人。

  2. 检查程序是否是第一次 运行 并仅在程序本身中执行与上述相同的操作。

  3. 如果未找到联系人 ID,则同样退出搜索循环,并且 return 一个未清除的联系人,所有变量都设置为空。

写到这里,想到三个问题:

其中哪一个是最好的或最容易使用的?

return 未申报的联系人安全吗? (我必须记住,我必须使用联系人:修改、打印、打印所有联系人)

我是否应该有一个结构和文件来记录一些未在联系人中使用的变量的统计信息structure/file?

尝试下面的方法,线性复杂度,如果没有contact,则初始化为0。

/* initialize memory */
memset(person, 0, MAXCONTACT * sizeof(contact0);

/* open the file */
data=fopen("data.bin","rb");

/* get the file size */
fseek(data, 0L, SEEK_END);

/* don't read more than your allocated array can contain */
int size = max(ftell(data), MAXCONTACT * sizeof(contact));

/* seek to the beginning of the file */
fseek(fp, 0L, SEEK_SET);

/* populate the array */
fread(&person,size,1,data);

/* close the file */
fclose(data);   

试试这个。它 returns 指示数据读取成功或失败,如果有效则返回 0,否则返回 -1(请注意,我将 "i" 更改为无符号,因为无法正确处理负值):

int load(unsigned int i, struct contact *person)
{
    int data;
    struct stat sb;
    data=open("data.bin", O_RDONLY);
    if ( data == -1 ) return( -1 );
    /* use fstat() to tell how big a file is */
    fstat( data, &sb );
    /* sb.st_size now holds the number of bytes in the file
       it needs to be at least as big as ( i + 1 ) contacts */
    if ( sb.st_size < ( ( 1 + i ) * sizeof( *person ) ) )
    {
        close( data );
        return( -1 );
    }
    /* seek to record i */
    lseek( data, ( i * sizeof( *person ) ), SEEK_SET );
    ssize_t bytesRead = read( data, person, sizeof( *person ) );
    /* return -1 if the read didn't get enough bytes */
    if ( bytesRead != sizeof( *person ) )
    {
        close( data );
        return( -1 );
    }
    close(data);
    return( 0 );
}

这将使调用者知道读取是否成功。

您必须更改代码以传递要填写的联系人结构的地址,但您会知道读取是否有效。