第14章 结构和其他数据形式 14.8 把结构内容保存到文件中

由于结构能保存多种多样的信息,所以它是建立数据库的重要工具。一个结构中保存的整套信息用术语来说就是一个记录,单个的项目称为字段。

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

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

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

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

14.8.1  一个结构保存的实例

我们改写程序清单14.2中的程序,把书名保存到一个名为book.bat的文件中。如果该文件存在,程序显示文件当前内容,然后允许您向文件中添加内容。程序清单14.14即是新版本。

/*booksave.c  --把结构内容保存到文件中*/

#include <stdio.h>
#include <stdlib.h>
#define MAXTITL 40
#define MAXAUTL 40
#define MAXBKS 10
struct 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.bat","a+b"))==NULL)
    {
        fputs("Can't open book.bat 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);
    }

    puts("Please add new book titles.");
    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[count].title,library[count].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;
}

14.8.2  程序要点

首先,使用“a+b"模式打开文件。a+部分允许程序读入整个文件,并向文件末尾添加数据。b是ANSI表示程序要使用二进制文件格式的方法。

我们选择二进制模式是因为fread()和fwrite()要使用二进制文件。的确,结构中有些内容是文本,但value成员不是文本,如果使用文本编辑器来查看book.dat,文本部分会正确显示,但是数字部分不可读,甚至还可能导致文本编辑器显示乱码。

命令rewind()确保文件指针处于文件开始位置,为开始读取做好准备

最开始的那个while循环每次把一个结构读到结构数组中,当数组满或文件读完时停止。变量filecount用来保存已读结构的数目。

接下来的while循环提示并获取用户输入。当数组 满或用户在一行开始就按下enter,退出循环。注意,开始循环时,变量count具有前面那个循环之后的值。这将把新的输入项添加到数组 的末尾。

然后,for循环打印来自文件和来自用户的数据。因为文件是以追加模式打开的,所以将把新写入的内容追加到已有内容的后面。

我们本来可以使用一个循环每次把一个结构添加到文件末尾。但是我们决定使用fwrite()一次写入多个块的功能。表达式count-filecount得出要加入的新书的数目,函数调用fwrite()把这么多数目的book结构大小的块写入到文件中。表达式library[filecount]是数组中第一个新输入的结构的地址,因此复制就从这一点开始。

这个例子或许就是将结构写入文件和取回结构的最简单的方法。但是它浪费了空间,因为结构中没使用的部分也被保存了。这个结构的大小是2*40*sizeof(char)+sizeof(float),在我们的系统中占84字节,事实上,不是每一个输入都需要这么多的空间。但是每个数据块具有同样大小,会使取回数据时更加容易。

转载于:https://my.oschina.net/idreamo/blog/866618

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值