C Primer Plus学习 四十九 把结构内容保存到文件中

        由于结构可以保存多种多样的信息,所以它是建立数据库的重要工具。例如,可以使用-个结构来保 存有关一个雇员或汽车零件的所有相关信息。最终,您会希望把这些信息保存在一个文件中,并能在以后 从文件中取回它们。一个数据库文件能够包含任意数目的此类数据对象。一个结构中保存的整套信息用术 语来称就是一个记录(record),单个的项目称为字段(field)。我们来探讨这些问题。

        或许最显而易见的也是最没效率的保存记录的方法就是使用fprintf()。

#define MAXTITL 40

#define MAXAUTL 40 struct book {

char title[MAXTITL]; 

char author[MAXAUTL];

 float value:

}:

       如果pbooks代表一个文件流,您可以用下列语句保存名为primer的struct book变量中的信息:
fprintf (pbooks, "%s %s %.2f\n", primer.title, primer.author, primer.value);

        对于一些结构(比如有30个成员的结构),这个方法用起来很不方便。另外,在取回数据时它还存在 问题,w为程序需要知道一个字段结束、另一个字段开始的位置。使用固定大小宽度的格式可以解决这个问题,%39s%39s%8.2f,但这个方法仍然很笨拙。

       一个更好的解决方法是使用fread ()和fwrite ()函数以结构的大小为单元进行读写。回忆--下,这 些函数在读写时使用了与程序所使用的相同的二进制表示法。例如:

fwrite (&primer, sizeof (struct book), 1, pbooks):

        这个语句定位到结构primer的开始地址,将该结构的所有字节复制到与pbooks相关联的文件中。sizeof (structbook)告诉函数要复制的每一块有多大,1表示只需要复制一块。具有同样参数的fread ()函数将 把一个结构大小的'块数据从文件复制到&primer指向的位置。简单地说,这些函数一次性读写整个记录,而不是一个字段。

        为了说明在程序中如何使用这些函数,我们看下面程序:

//* book.c --仅包含一本书的图书目录V

#include<stdio.h>

#define MAXTITL 41           //*书名的最大长度+1 V 

#define MAXAUTL 31           /*作者名的最大长度+1 */

#define MAXBKS 10            //*最多可以容纳的图书册数

struct book{                 /*结构模板:标记为book */

char title[MAXTITL];

char author[MAXAUTL];

float value;

};/*结构模板结束*/

int main(void)

{

struct book library[MAXBKS];    /* 结构数组 */

int count=0;

int index,filecount;

FILE *pbooks;

int size=sizeof(struct book);

if((pbooks=fopen("book.dat","a+b"))==NULL)

{

fputs("Can't open book.dat file\n",stderr);

exit(1);

}

rewind(pbooks);

while(count<MAXBKS&&fread(&library[count],size,1,pbooks)==1)

{

if(count==0)

{

puts("Current contents of book.dat");

}

printf("%s by %s:$%.2f\n",library[count].title,library[count].author,library[count].value);

count++;

}

filecount=count;

if(count==MAXBKS)

{

fputs("the book.dat file is full.",stderr);

exit(2);

}

    printf("please enter the book title.\n");

    puts("Press[enter] at the start of a line to stop.");

    while(count<MAXBKS&&gets(library[count].title)!=NULL&&library[count].title[0]!='\0')

    {

    puts("Now enter the author:");

    gets(library[count].author);

    puts("Now enter the value:");

    scanf("%f",&library[count].value);

    while(getchar()!='\n')

       continue;

   if(count<MAXBKS)

            puts("Enter the next title.");

    }

    if(count>0)

    {

    puts("Here is the list of your books:");

    for(index=0;index<count;index++)

    {

   printf("%s by %s:$%.2f\n",library[index].title,

    library[index].author,library[count].value);

       fwrite(&library[filecount],size,count-filecount,pbooks);

   }

    }

else{

    puts("No books? too bad.\n");

    }

puts("bye.\n");

fclose(pbooks);

return 0;

}

运行示例
Please add new book titles.
Press [enter] at the start of a line to stop.
Metric Merrlnent Now enter the author.
Polly Poetica Now enter the value.
18.99

Enter the next title.

D«adly Farce

Now enter the author.

Dudley Porse

Now enter the value.

15.99

Enter the next title.

[ant«r]

Here is the list of your books:

Metric Merriment by Polly Poetica: $18.99 Deadly Farce by Dudley Forse: $15.99 Bye.

       首先,使用”a+b”模式打开文件。a+部分允许程序读入整个文件,并向文件末尾添加数据。b是ANSI 表示程序要使用二进制文件格式的方法。对不接受b的UNIX系统来说,可以省略b,因为UNIX总共只 有一种文件形式。对其他的ANSI之前的实现,您可能需要找到b的等价表示法。
       我们选择二进制模式是因为firead ()和fWrite ()要使用二进制文件。的确,结构中有些内容是文本, 但value成员不是文本。如果使用文本编辑器来査看boofc.dat,文本部分会正确显示,但是数字部分不可读, 甚至还可能导致文本编辑器显示乱码。
        命令rewind ()确保文件位置指针处于文件开始部分,为开始读取做好准备。
最开始的那个while循环每次把一个结构读到结构数组中,当数组满或文件读完时停止。变量fi〗ecount 用来保存已读结构的数目。
        接下来的while循环提示并获取用户输入。像程序清单14.2所示那样,当数组满或用户在一行开始就 按下回车键时,退出循环。注意,开始循环时,变量count具有前面那个循环之后的值。这将把新的输入 项添加到数组的末尾。 •
然后,for循环打印来自文件和来自用户的数据。因为文件是以追加模式打开的,所以将把新写入的内 容追加到已有内容后面。
        我们本来可以使用一个循环来每次把一个结构添加到文件末尾。但是,我们决定使用fWrite () —次 写入多个块的功能。表达式counffilecount得出要加入的新书的数目,函数调用fwrite ()把这么多数目的 bodk.结构大小的块写入到文件中。表达式&libraiy[filecount]是数组中第一个新输入的结构的地址,因此复制就从这一点开始。




评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值