前言
我们会在前面实现静态、动态数据库的时候,输入一组数据,完成一系列增删改查之后,程序关闭,下次再打开的时候,会发现之前的数据没有了,这是因为,我们的数据都是存放在内存中,当程序结束的时候,自然内存释放了,再打开就没有了。
那么,如果通过文件操作,将程序中的数据,传递给硬盘中,下次使用再拿出可以吗?
当然可行啊,我们就带大家操作一下。
一、使用文件操作思路
我们要在原来通讯录上更改什么?
1.退出保存数据 所以在输入0退出的时候,加上文件操作,使得数据保存到相应的文件中
2.打开程序就提取出之前数据 这个在初始化的时候,使用文件操作,即可
以上两点进行修改就可以完善通讯录,实现可以存取数据的通讯录,更加实用
二、使用步骤
1.退出改造
如图所示:
代码如下:
void SaveContact(Contact* pc) { //存入数据 //使用fwrite 二进制存储吧 //fopen打开文件 FILE* pf = fopen("Contact.txt", "wb"); //判断是否存在文件Contact.txt if (NULL == pf) { perror("SaveContact::fopen"); } else { fwrite(pc->data, sizeof(PeopleInfo), pc->sz, pf); //输出之后提示输出完成到Contact.txt中 printf("保存完成\n"); //关闭流 并pf置为NULL 防止野指针 fclose(pf); pf = NULL; } }
2.初始化改造
我们想要一开始就得到原来的数据,我们在初始化的时候,就读取Contact.txt文件中的数据即可
图示如下:
代码如下:
//新增代码,读取文件中的数据 void read_Contact(Contact* pc) { //读取的时候先进行判断是否 FILE* pf = fopen("Contact.txt", "r"); if (NULL == pf) { perror("read_Contact::open"); } else { PeopleInfo ptr={0}; int i = 0; while (fread(&ptr, sizeof(PeopleInfo), 1, pf)) { check_capacity(pc); //不够就扩容 pc->data[i] = ptr; pc->sz++; i++; } } } void check_capacity(Contact* pc) { if (pc->sz == pc->capacity) { //使用realloc函数 进行扩容 PeopleInfo* ptr = (PeopleInfo*)realloc(pc->data, sizeof(PeopleInfo) * (pc->capacity + MAX2)); if (ptr == NULL) { perror("check_capacity"); return; } else { pc->data = ptr; pc->capacity = pc->capacity + MAX2; printf("扩容完成\n"); } } } //这是动态通讯录的初始化 void InitContact(Contact* pc) { //进行初始化的时候,我们当然可以直接 assert(pc);//断言 pc->sz = 0; PeopleInfo *ptr=(PeopleInfo*)calloc(MAX1,sizeof(PeopleInfo)); if (ptr == NULL) { perror("malloc::data"); return; } pc->data = ptr; pc->capacity=MAX1; read_Contact(pc); }
3.代码演示
如图所示,这样就可以实现在硬盘文件中输入读取数据,更加贴合实际所需,这就是经过文件操作处理之后的动态通讯录,静态更简单,会了动态,静态就可以实现。
三、文件操作通讯录完整代码
我们分成了三部分,Contact.h Contact.c test.c
Contact.h 声明test.c所需要的函数 是头文件
Contact.c 实现Contact.h声明的函数
test.c 通讯录的主体。主干,实现通讯录的逻辑
1.Contact.h
#define _CRT_SECURE_NO_WARNINGS //Contact 实现通讯录 头文件 #include<stdio.h> #include<string.h> #include<assert.h> #include<malloc.h> #include<stdlib.h> #include<search.h> #define MAX 100 #define NAME_MAX 20 #define SEX_MAX 5 #define ADDR_MAX 20 #define TELE_MAX 12 //下面两个define是用于动态通讯录的 #define MAX1 3 //表示第一次容积是多少 #define MAX2 2 //表示一次扩容多少 //构建通讯录所需的结构体 typedef struct PeopleInfo { char name[NAME_MAX];//姓名 int age;//年龄 char sex[NAME_MAX];//性别 char addr[ADDR_MAX];//地址 char tele[TELE_MAX];//电话号码 }PeopleInfo; //这是静态通讯录 就是data这个数组是固定死的MAX //typedef struct Contact { // PeopleInfo data[MAX];//表示存储的通讯录最大人员数 // int sz;//表示当前Contact通讯录人员个数 //}Contact; //实现动态通讯录 typedef struct Contact { PeopleInfo *data;//表示存储的通讯录最大人员数 int sz;//表示当前Contact通讯录人员个数 int capacity; //表示当前容量 作为扩容的依据 }Contact; //初始化通讯录 void InitContact(Contact* pc); //添加通讯录的信息 void addContact(Contact* pc); //删除通讯录中的信息 void delContact(Contact* pc); //查找通讯录成员信息 int searchContact(Contact* pc); //打印 void showContact(Contact* pc); //改变指定元素 void changeContact(Contact* pc); //排序,按照名字排序 void sortContact(Contact* pc); //保存通讯录 void SaveContact(Contact*pc); //读取通讯录 void read_Contact(Contact*pc);
2.Contact.c
#define _CRT_SECURE_NO_WARNINGS #include"Contact.h" //用来实现头文件的代码 // 这是静态初始化 //void InitContact(Contact* pc) { // //进行初始化的时候,我们当然可以直接 // pc->sz = 0; // memset(pc->data, 0, sizeof(pc->data)); // //memset 函数 这样的话,从data这个数组的地址开始 sizeof(pc->data)个字节,都赋值为0 //} //这是动态通讯录的初始化 void InitContact(Contact* pc) { //进行初始化的时候,我们当然可以直接 assert(pc);//断言 pc->sz = 0; PeopleInfo *ptr=(PeopleInfo*)calloc(MAX1,sizeof(PeopleInfo)); if (ptr == NULL) { perror("malloc::data"); return; } pc->data = ptr; pc->capacity=MAX1; read_Contact(pc); } 静态通讯录 //void addContact(Contact* pc) { // assert(pc); // if (pc->sz == MAX) { // printf("通讯录已满,无法添加\n"); // return; // } // printf("请输入名字:>"); // scanf("%s", pc->data[pc->sz].name); // printf("请输入年龄:>"); // scanf("%d", &(pc->data[pc->sz].age)); // printf("请输入性别:>"); // scanf("%s", pc->data[pc->sz].sex); // printf("请输入地址:>"); // scanf("%s", pc->data[pc->sz].addr); // printf("请输入电话:>"); // scanf("%s", pc->data[pc->sz].tele); // printf("添加完成,请继续操作\n"); // pc->sz++; //} //动态通讯录 void check_capacity(Contact* pc) { if (pc->sz == pc->capacity) { //使用realloc函数 进行扩容 PeopleInfo* ptr = (PeopleInfo*)realloc(pc->data, sizeof(PeopleInfo) * (pc->capacity + MAX2)); if (ptr == NULL) { perror("check_capacity"); return; } else { pc->data = ptr; pc->capacity = pc->capacity + MAX2; printf("扩容完成\n"); } } } void addContact(Contact* pc) { assert(pc); check_capacity(pc); printf("请输入名字:>"); scanf("%s", pc->data[pc->sz].name); printf("请输入年龄:>"); scanf("%d", &(pc->data[pc->sz].age)); printf("请输入性别:>"); scanf("%s", pc->data[pc->sz].sex); printf("请输入地址:>"); scanf("%s", pc->data[pc->sz].addr); printf("请输入电话:>"); scanf("%s", pc->data[pc->sz].tele); printf("添加完成,请继续操作\n"); pc->sz++; } void delContact(Contact* pc) { assert(pc); printf("请选择删除的目标:>"); if (pc->sz == 0) { return; } //删除的话只需要找到对应的要删除的数据,比如以名字为准,先找到,然后再讲其后面的元素覆盖前面的 int pos = searchContact(pc); //换位置 if (pos == -1) { printf("没有查找到该成员\n"); return; } for (int i = pos; i < pc->sz - 1; i++) { pc->data[i] = pc->data[i + 1]; } pc->sz--;//直接--不用管换位置之后最后一个数字的问题 printf("删除完成\n"); } int searchContact(Contact* pc) { assert(pc); char name[20]; int pos = -1; scanf("%s", name); //查询 for (int i = 0; i < pc->sz; i++) { if (strcmp(pc->data[i].name, name) == 0) { pos = i; } } return pos; } void showContact(Contact* pc) { assert(pc); if (pc->sz == 0) { return; }//可以有可无 printf("%-20s\t%-5s\t%-5s\t%-20s\t%-12s\n", "姓名", "年龄", "性别", "地址", "电话"); for (int i = 0; i < pc->sz; i++) { printf("%-20s\t%-5d\t%-5s\t%-20s\t%-12s\n", pc->data[i].name, pc->data[i].age, pc->data[i].sex, pc->data[i].addr, pc->data[i].tele); } printf("打印完成\n"); } void changeContact(Contact* pc) { assert(pc); //先找到 int pos = searchContact(pc); printf("请输入名字:>"); scanf("%s", pc->data[pos].name); printf("请输入年龄:>"); scanf("%d", &(pc->data[pos].age)); printf("请输入性别:>"); scanf("%s", pc->data[pos].sex); printf("请输入地址:>"); scanf("%s", pc->data[pos].addr); printf("请输入电话:>"); scanf("%s", pc->data[pos].tele); printf("更改完成, 请继续操作\n"); } void sortContact(Contact* pc) { assert(pc); if (pc->sz == 0) { printf("通讯录中暂无元素\n"); return; } Contact s; InitContact(&s); for (int i = 0; i < pc->sz-1; i++) { for (int j = 0; j < pc->sz-1-i; j++) { if (strcmp(pc->data[j].name, pc->data[j + 1].name)==1) { s.data[j] = pc->data[j]; pc->data[j] = pc->data[j + 1]; pc->data[j + 1] = s.data[j]; } } } } int compare(const void* e1, const void* e2) { return *((int*)e1) - *((int*)e2); } void sort(Contact*pc) { qsort(pc->data, pc->sz, sizeof(pc->data[0]), compare); } //int main() // //{ // qsort() // return 0; //} void SaveContact(Contact* pc) { //存入数据 //使用fwrite 二进制存储吧 //fopen打开文件 FILE* pf = fopen("Contact.txt", "wb"); //判断是否存在文件Contact.txt if (NULL == pf) { perror("SaveContact::fopen"); } else { fwrite(pc->data, sizeof(PeopleInfo), pc->sz, pf); //输出之后提示输出完成到Contact.txt中 printf("保存完成\n"); //关闭流 并pf置为NULL 防止野指针 fclose(pf); pf = NULL; } } void read_Contact(Contact* pc) { //读取的时候先进行判断是否 FILE* pf = fopen("Contact.txt", "r"); if (NULL == pf) { perror("read_Contact::open"); } else { PeopleInfo ptr={0}; int i = 0; while (fread(&ptr, sizeof(PeopleInfo), 1, pf)) { check_capacity(pc); //不够就扩容 pc->data[i] = ptr; pc->sz++; i++; } } }
3.test.c
#define _CRT_SECURE_NO_WARNINGS #include"Contact.h" //这边进行主要的通讯录流程操作 void menu() { printf("***********************************************\n"); printf("****** 1.add 2.del ******\n"); printf("****** 3.search 4.change ******\n"); printf("****** 5.show 6.sort ******\n"); printf("****** 0.exit ******\n"); printf("***********************************************\n"); } void test() { //打印选择菜单 int input = 0; int pos = 0; Contact pc; //Contact pc={0}; //当然可以这样初始化,但是不一定后来初始化都这样,所以有InitContact() InitContact(&pc); do { menu(); printf("请选择:>"); scanf("%d", &input); switch (input) { case 1: addContact(&pc); break; case 2: delContact(&pc); break; case 3: pos = searchContact(&pc); if (pos == -1) { printf("没有查找到该成员\n"); } else { printf("%-20s\t%-5d\t%-5s\t%-20s\t%-12s\n", pc.data[pos].name, pc.data[pos].age, pc.data[pos].sex, pc.data[pos].addr, pc.data[pos].tele); } break; case 4: changeContact(&pc); break; case 5: showContact(&pc); break; case 6: sort(&pc); break; case 0: SaveContact(&pc); printf("退出通讯录\n"); free(pc.data); break; default: break; } } while (input); } int main() { test(); return 0; }
总结
本文通过文件操作实现了,通讯录的数据存储到硬盘上,并可以从硬盘中读取数据到程序中,所以这是更加贴合实际所需了,我们介绍了主要文件操作运用的地方,以及实现方式,并附带了完整的代码,希望友友们,能看懂并理解这样的程序。
小王在这里提前祝大家2023兔年新年快乐!!!