或许最显而易见的也是最没效率的保存记录的方法就是使用fprintf()。
如果pbooks代表一个文件流,您可以用下列语句保存名为primer的struct book变量中的信息:#define MAXTITL 40
#define MAXAUTL 40 struct book {
char title[MAXTITL];
char author[MAXAUTL];
float value:
}:
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.首先,使用”a+b”模式打开文件。a+部分允许程序读入整个文件,并向文件末尾添加数据。b是ANSI 表示程序要使用二进制文件格式的方法。对不接受b的UNIX系统来说,可以省略b,因为UNIX总共只 有一种文件形式。对其他的ANSI之前的实现,您可能需要找到b的等价表示法。
Press [enter] at the start of a line to stop.
Metric Merrlnent Now enter the author.
Polly Poetica Now enter the value.
18.99Enter 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.
我们选择二进制模式是因为firead ()和fWrite ()要使用二进制文件。的确,结构中有些内容是文本, 但value成员不是文本。如果使用文本编辑器来査看boofc.dat,文本部分会正确显示,但是数字部分不可读, 甚至还可能导致文本编辑器显示乱码。
命令rewind ()确保文件位置指针处于文件开始部分,为开始读取做好准备。
最开始的那个while循环每次把一个结构读到结构数组中,当数组满或文件读完时停止。变量fi〗ecount 用来保存已读结构的数目。
接下来的while循环提示并获取用户输入。像程序清单14.2所示那样,当数组满或用户在一行开始就 按下回车键时,退出循环。注意,开始循环时,变量count具有前面那个循环之后的值。这将把新的输入 项添加到数组的末尾。 •
然后,for循环打印来自文件和来自用户的数据。因为文件是以追加模式打开的,所以将把新写入的内 容追加到已有内容后面。
我们本来可以使用一个循环来每次把一个结构添加到文件末尾。但是,我们决定使用fWrite () —次 写入多个块的功能。表达式counffilecount得出要加入的新书的数目,函数调用fwrite ()把这么多数目的 bodk.结构大小的块写入到文件中。表达式&libraiy[filecount]是数组中第一个新输入的结构的地址,因此复制就从这一点开始。