【问题标题】:unable to read struct from a binary file using C when file is not 100% filled as expected当文件未按预期 100% 填充时,无法使用 C 从二进制文件中读取结构
【发布时间】:2015-04-09 19:01:32
【问题描述】:

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

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)的函数,返回具有相同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 个联系人时,该函数不会返回联系人,因为找不到联系人 ID。

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

  1. 制作一个像真正的安装程序一样创建文件的安装程序,然后创建 200 个未声明的联系人,其变量等于 null。

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

  3. 如果未找到联系人 ID,则同样退出搜索循环并返回所有变量设置为 null 的未清除联系人。

写完之后,想到三个问题:

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

返回未清除的联系人是否安全? (我必须记住,我必须使用联系人:modefy,打印,打印所有联系人)

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

【问题讨论】:

  • 始终检查fread结果,无论选择何种方法。至于“返回未清除的联系人是否安全?”,当然,如果您知道如何处理的话。一切尽在您的掌控之中。
  • 然后.. 打开文件并搜索 id,然后关闭 each 联系人 id??有点……尴尬,说话温和。
  • @EugeneSh。没错,我可以写一些 if 来检查变量中是否有内容
  • @EugeneSh。那我该怎么做呢?
  • 打开文件,逐个读取联系人,填充数组,关闭文件。

标签: c file struct


【解决方案1】:

试试下面的方法,线性复杂度,如果一个接触不存在,就会初始化为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);   

【讨论】:

  • SEEK_SET 是做什么的?
  • 我对 max 有无限的参考!
  • fseek() 改变从输入流中读取的下一个字符的位置。命令 fseek(data, 0L, SEEK_END);将位置移动到流的末尾(为了使用 ftell() 获取它的大小) fseek(fp, 0L, SEEK_SET);将位置倒回到流的开头,因为您想将流读入数组。要解决未定义的引用,请包含 math.h:#include
  • 这是我的错误,max 没有在 math.h 中定义。以下是如何定义这个宏:#define max(a, b) (((a) > (b)) ? (a) : (b))
【解决方案2】:

试试这个。它返回指示数据读取是否有效,如果有效则返回 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 );
}

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

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2011-05-08
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-05-16
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多