前言:
上期通讯录我们实现了动态内存的申请,但数据依然是存放在内存中,当程序退出的时候,通讯录中的数据自然就不存在了,等下次运行通讯录程序的时候,数据又得重新录入。
这一期继续改造,让通讯录更加实用,能够实时保存练习人信息。
1.实时保存如何实现?
这就涉及到了数据持久化的问题:
一般 数据持久化的方法有:
把数据存放在磁盘文件、存放到数据库等方式。
使用文件,我们可以将数据直接存放在电脑的硬盘上,做到了数据的持久化。
所以我们的思路就是在原来录入联系人信息时 将信息存放在文件中, 退出时自动保存。
2. 相关函数介绍
2.1 fopen
fopen 函数的作用是打开指定的文件;
返回值:
如果打开文件成功,返回指向要打开文件的文件指针;
如果打开文件失败,返回 NULL;
所以函数的返回值要做检查;
传参:
filename : 要打卡文件的名称(包含后缀);
mode : 使用的方式,yi
2.2 fclose
很直观,作用是关闭文件;
返回值:
如果关闭成功,返回 0;
如果关闭失败,返回 EOF;
传参:
指向要关闭文件的文件指针;
使用文件,养成好习惯:
打开文件 --> 相关操作 --> 关闭文件
#include<stdio.h> void File(Test* pc) { FILE* pf = fopen("test.txt", "rb"); //检查返回值 if (pf == NULL) { perror("Test"); return; } //操作... //关闭文件 fclose(pf); pf = NULL; }
2.3 fread
fread 作用是将文件中的信息读取到一块内存缓冲区中;
返回值:
实际从文件中读取的基本单元个数;
传参:
ptr : 将文件中的二进制数据读取到的缓冲区;
size : 一次读取的基本单元大小,单位是字节;
count : 一次读取的单元个数;
stream : 文件指针,指向要读取的文件。
2.4 fwrite
fwrite 作用是 把数据写入文件中;
返回值:
实际从内存中写入文件的 基本单元个数;
传参:
与 fread 类似,将读取改为写入。
3.实现过程
在原有的代码上做修改,只需在退出通讯录时保存通讯录,在初始化通讯录时加载通讯录即可。
保存通讯录部分:
void Save_Contact(Contact* pc) { FILE* pf = fopen("contact.txt", "wb"); if (pf == NULL) { perror("Save_Contact"); } else { //写入数据 int i = 0; for (i = 0; i < pc->sz; i++) { fwrite(pc->data+i, sizeof(PeoInform), 1, pf); } fclose(pf); pf = NULL; printf("保存成功\n"); } }
这一部分用到了 fwrite 函数,将数据写入文件中。
加载通讯录部分:
void Load_Contact(Contact* pc) { FILE* pf = fopen("contact.txt", "rb"); if (pf == NULL) { perror("Load_Contact"); } else { //读数据 PeoInform tmp = { 0 }; int i = 0; while (fread(&tmp, sizeof(PeoInform), 1, pf)) { check_capacity(pc); pc->data[i] = tmp; pc->sz++; i++; } fclose(pf); pf = NULL; } }
这一部分主体上用 fread 函数来实现,读取文件中的数据;
巧妙的是:
直接将 fread 的返回值作为 while 循环的判断条件:
因为每次只读一个单位的数据,读取成功返回 1 ,到了文件末尾,读取不到数据了,就返回 0 ,跳出循环。
总结:
本次通讯录的升级应用到了文件操作的相关知识,掌握了文件操作,数据持久化就不是问题啦 ~