C语言文件操作

前面两期我们都在完善我们的通讯录的工作,在上一期我们将通讯录由静态内存转为了动态内存的版本,但是他还是有缺陷,因为我们每次打开程序都需要把通讯录里的内容重新输入,程序一旦结束这些东西就没了,下次打开又要重新一个一个的输入,那有没有什么办法能让我们在退出程序之前先把通讯录中的内容保存下来呢?当然有了,这就要提到了我们的文件操作

使用文件我们可以将数据直接存放在电脑的硬盘上,做到了数据的持久化

一、文件的打开和关闭

1.1 文件指针

每当打开一个文件的时候,系统会根据文件的情况自动创建一个FILE结构的变量,并填充其中的信息,使用者不必关心细节。一般都是通过一个FILE的指针来维护这个FILE结构的变量,这样使用起来更加方便。

我们可以创建一个文件指针变量

1.2 文件的打开和关闭

在进行文件的读写操作之前我们要先打开文件,使用完之后要关闭文件

因此需要用到两个库函数fopen和fclose

因此我们可以看到文件打开和关闭的格式为:

fopen的打开方式如下:

举个例子:

cpp 复制代码
int main()
{
	//打开文件
	FILE* pf = fopen("text.txt", "w");
	if (pf == NULL)
	{
		perror("fopen");
		return 1;
	}
	//使用
	fputs("I am iron man!\n", pf);
	fputs("hello fox!\n", pf);
	//关闭文件
	fclose(pf);
	pf = NULL;
	return 0;
}

1.3 文件读写函数

二、通讯录3.0版本

有了前面的知识之后我们就可以将我们通讯录中的内容写进通讯录中

2.1 保存通讯录

首先我们需要将之前的主函数修改一下,增加一个保存数据的函数

cpp 复制代码
int main()
{
	int input = 0;
	//创建通讯录
	context con;
	//初始化通讯录
	init_context(&con);
	do
	{
		menu();
		printf("请选择:");
		scanf("%d", &input);
		switch (input)
		{
		case ADD:
			add_context(&con);
			break;
		case DEL:
			del_context(&con);
			break;
		case SEARCH:
			serch_context(&con);
			break;
		case MODIFY:
			modify_contest(&con);
			break;
		case SHOW: 
			show_context(&con);
			break;
		case SORT:
			sort_context(&con);
			break;
		case CLN:
			cln_context(&con);
			break;
		case EXIT:
			save_context(&con);
			distory_context(&con);
			printf("退出通讯录");
			break;
		default:
			printf("输入错误,请重新输入\n");
			break;
		}
	} while (input);
	return 0;
}

保存数据的函数其实就是将当前通讯录中的数据写出到文件中,下次运行的时候现把通讯录文件的内容读取到程序中就可以了

在写入文件的时候我们可以一个人的信息写一次,一个一个的把输入好的信息直接存入到文件中

cpp 复制代码
void save_context(context* pc)
{
	//写数据
	//1. 打开文件
	FILE* pf = fopen("context.txt", "wb");
	if (NULL == pf)
	{
		perror("save_context::fopen");
	}
	else
	{
		//2. 写入数据
		int i = 0;
		for (i = 0; i < pc->sz; i++)
		{
			fwrite(&(pc->data[i]), sizeof(peo_info), 1, pf);
		}
		fclose(pf);
		pf = NULL;
		printf("保存成功\n");
	}
}

2.2 加载通讯录

保存好了之后每次打开前我们都先将文件中的数据加载进来,因此我们还需要一个加载的函数(ps. 因为我们在清空通讯录的函数里面需要用到初始化函数,因此这里需要设置在初始化函数中只能使用一次加载函数)

cpp 复制代码
int count = 1;
void init_context(context* pc)
{
	assert(pc);
	pc->sz = 0;
	peo_info* ptr = (peo_info*)calloc(MAX,sizeof(peo_info));
	if (ptr == NULL)
	{
		perror("init_context::calloc");
		return;
	}
	pc->data = ptr;
	int i = 0;
	for (i = 0; i < DEFAULE_SZ; i++)
	{
		memset(&(pc->data[i]), 0, sizeof(pc->data[i]));
	}
	pc->capacity = DEFAULE_SZ;

	//加载文件信息到通讯录
	
	if (count)
	{
		load_context(pc);
		count--;
	}
}
cpp 复制代码
void load_context(context* pc)
{
	//打开文件
	FILE* pf = fopen("context.txt", "rb");
	if (pf == NULL)
	{
		perror("load_context");
	}
	else
	{
		//将文件中的数据读取到通讯录中
		
		peo_info tmp = { 0 };
		int i = 0;
		//读数据
		while (fread(&tmp, sizeof(peo_info), 1, pf))
		{
			check_capacity(pc);
			pc->data[i] = tmp;
			i++;
			pc->sz++;
		}
		fclose(pf);
		pf = NULL;
	}
}

这样我们就得到了最终版本的通讯录,太不容易了!!!

来看看效果吧

三、通讯录全代码

代码奉上

text.c

cpp 复制代码
#define  _CRT_SECURE_NO_WARNINGS 1;

#include"context.h"

void menu()
{
	printf("****************************************\n");
	printf("******     1. add     2. del    ********\n");
	printf("******     3. search  4. modify ********\n");
	printf("******     5. show    6.sort    ********\n");
	printf("******     7. cln     0. exit   ********\n");
	printf("****************************************\n");

}

int main()
{
	int input = 0;
	//创建通讯录
	context con;
	//初始化通讯录
	init_context(&con);
	do
	{
		menu();
		printf("请选择:");
		scanf("%d", &input);
		switch (input)
		{
		case ADD:
			add_context(&con);
			break;
		case DEL:
			del_context(&con);
			break;
		case SEARCH:
			serch_context(&con);
			break;
		case MODIFY:
			modify_contest(&con);
			break;
		case SHOW: 
			show_context(&con);
			break;
		case SORT:
			sort_context(&con);
			break;
		case CLN:
			cln_context(&con);
			break;
		case EXIT:
			save_context(&con);
			distory_context(&con);
			printf("退出通讯录");
			break;
		default:
			printf("输入错误,请重新输入\n");
			break;
		}
	} while (input);
	return 0;
}

context.h

cpp 复制代码
#define  _CRT_SECURE_NO_WARNINGS 1;

#include <stdio.h>
#include <string.h>
#include <assert.h>
#include <stdlib.h>

#define MAX 100
#define NAME_MAX 20
#define SEX_MAX 5
#define TELE_MAX 12
#define ADDR_MAX 15

#define DEFAULE_SZ 3
#define INC_SZ 2

//声明选项
enum option
{
	EXIT,
	ADD,
	DEL,
	SEARCH,
	MODIFY,
	SHOW,
	SORT,
	CLN,
};

typedef struct peo_info
{
	char name[NAME_MAX];
	int age;
	char sex[SEX_MAX];
	char tele[TELE_MAX];
	char addr[ADDR_MAX];
}peo_info;

静态版本
//typedef struct context
//{
//	peo_info data[MAX];//存放人的信息
//	int sz;//存放当前存的人的个数
//}context;

//动态版本
typedef struct context
{
	int sz;//存放当前存的人的个数
	int capacity;//当前通讯录的最大容量
	peo_info* data;//存放人的信息
}context;

//检查容量
void check_capacity(context* pc);

//初始化通讯录
void init_context(context* pc);

//增加联系人
void add_context(context* pc);

//显示通讯录
void show_context(context* pc);

//删除联系人
void del_context(context* pc);

//查找联系人
void serch_context(context* pc);

//修改联系人
void modify_contest(context* pc);

//排序
void sort_context(context* pc);

//清空通讯录
void cln_context(context* pc);

//销毁通讯录
void distory_context(context* pc);

//保存通讯录
void save_context(context* pc);

context.c

cpp 复制代码
#define  _CRT_SECURE_NO_WARNINGS 1;

#include"context.h"

//静态版本
初始化通讯录
//void init_context(context* pc)
//{
//  assert(pc);
//	pc->sz = 0;
//	memset(pc->data, 0, sizeof(pc->data));
//}

void load_context(context* pc)
{
	//打开文件
	FILE* pf = fopen("context.txt", "rb");
	if (pf == NULL)
	{
		perror("load_context");
	}
	else
	{
		//将文件中的数据读取到通讯录中
		
		peo_info tmp = { 0 };
		int i = 0;
		//读数据
		while (fread(&tmp, sizeof(peo_info), 1, pf))
		{
			check_capacity(pc);
			pc->data[i] = tmp;
			i++;
			pc->sz++;
		}
		fclose(pf);
		pf = NULL;
	}
}


//动态版本
int count = 1;
void init_context(context* pc)
{
	assert(pc);
	pc->sz = 0;
	peo_info* ptr = (peo_info*)calloc(MAX,sizeof(peo_info));
	if (ptr == NULL)
	{
		perror("init_context::calloc");
		return;
	}
	pc->data = ptr;
	int i = 0;
	for (i = 0; i < DEFAULE_SZ; i++)
	{
		memset(&(pc->data[i]), 0, sizeof(pc->data[i]));
	}
	pc->capacity = DEFAULE_SZ;

	//加载文件信息到通讯录
	
	if (count)
	{
		load_context(pc);
		count--;
	}
}

//静态版本
//增加联系人
//void add_context(context* pc)
//{
//	assert(pc);
//	if (MAX == pc->sz)
//	{
//		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].tele);
//	printf("请输入地址:");
//	scanf("%s", pc->data[pc->sz].addr);
//	pc->sz++;
//	printf("添加成功\n");
//}


void check_capacity(context* pc)
{
	assert(pc);
	if (pc->sz == pc->capacity)
	{
		//增加容量
		pc->capacity += INC_SZ;
		printf("增容成功\n");
	}
	else
	{
		return;
	}
}

//动态版本
void add_context(context* 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].tele);
	printf("请输入地址:");
	scanf("%s", pc->data[pc->sz].addr);
	pc->sz++;
	printf("添加成功\n");
}


//显示通讯录
void show_context(context* pc)
{
	assert(pc);
	//判断通讯录是否为空
	if (pc->sz == 0)
	{
		printf("通讯录为空\n");
		return;
	}
	int i = 0;
	printf("%-10s\t%-4s\t%-4s\t%-13s\t%-10s\n", "姓名", "年龄", "性别", "电话", "地址");
	for (i = 0; i < pc->sz; i++)
	{
		printf("%-10s\t%-4d\t%-4s\t%-13s\t%-10s\n", pc->data[i].name,
			pc->data[i].age,
			pc->data[i].sex,
			pc->data[i].tele,
			pc->data[i].addr);
	}
}

int find_by_name(context* pc, char name[])
{
	int i = 0;
	for (i = 0; i < pc->sz; i++)
	{
		int ret = strcmp(pc->data[i].name, name);
		if (0 == ret)
		{
			return i;
		}
	}
	return -1;
}

//删除联系人
void del_context(context* pc)
{
	assert(pc);
	char name[NAME_MAX] = { 0 };
	if (0 == pc->sz)
	{
		printf("通讯录为空,无法删除\n");
		return;
	}
	printf("请输入要删除的人的名字:");
	scanf("%s", name);
	int ret = find_by_name(pc, name);
	if (-1 == ret)
	{
		printf("要删除的人不存在\n");
		return;
	}
	//删除
	int i = 0;
	for (i = ret; i < pc->sz - 1; i++)
	{
		pc->data[i] = pc->data[i + 1];
	}
	pc->sz--;
	printf("删除成功\n");
}

//void del_context(context* pc)
//{
//	assert(pc);
//
//	char name[NAME_MAX] = { 0 };
//	if (pc->sz == 0)
//	{
//		printf("通讯录为空,无法删除\n");
//		return;
//	}
//	删除
//	找到要删除的人
//	printf("请输入要删除的人的名字:>");
//	scanf("%s", name);
//	int ret = find_by_name(pc, name);
//	if (-1 == ret)
//	{
//		printf("要删除的人不存在\n");
//		return;
//	}
//
//	删除
//	int i = 0;
//	for (i = ret; i < pc->sz - 1; i++)
//	{
//		pc->data[i] = pc->data[i + 1];
//	}
//	printf("删除成功\n");
//}

//查找联系人
void serch_context(context* pc)
{
	assert(pc);
	char name[NAME_MAX] = { 0 };
	printf("请输入要查找的人的名字:");
	scanf("%s", name);
	int pos = find_by_name(pc, name);
	if (-1 == pos)
	{
		printf("要查找的人不存在\n");
		return;
	}
	else
	{
		printf("%-10s\t%-4s\t%-4s\t%-13s\t%-10s\n", "姓名", "年龄", "性别", "电话", "地址");
		printf("%-10s\t%-4d\t%-4s\t%-13s\t%-10s\n", pc->data[pos].name,
			pc->data[pos].age,
			pc->data[pos].sex,
			pc->data[pos].tele,
			pc->data[pos].addr);
	}
}

//void serch_context(context* pc)
//{
//	assert(pc);
//	char name[NAME_MAX] = { 0 };
//	printf("请输入要查找人的名字:>");
//	scanf("%s", name);
//	int pos = find_by_name(pc, name);
//	if (-1 == pos)
//	{
//		printf("要查找的人不存在\n");
//		return;
//	}
//	//打印信息
//	printf("%-20s\t%-4s\t%-5s\t%-20s\t%-12s\n", "名字", "年龄", "性别", "地址", "电话");
//	printf("%-20s\t%-4d\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);
//}

//修改联系人
void modify_contest(context* pc)
{
	printf("请输入要修改的人的名字:");
	char name[NAME_MAX] = { 0 };
	scanf("%s", name);
	//找人
	int pos = find_by_name(pc, name);
	if (-1 == pos)
	{
		printf("要修改的人不存在\n");
		return;
	}
	//修改
	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].tele);
	printf("请输入地址:");
	scanf("%s", pc->data[pos].addr);
	printf("修改成功\n");
}

//排序

//按年龄排序
int cmp_by_age(const void* p1, const void* p2)
{
	return (((peo_info*)p1)->age) - (((peo_info*)p2)->age);
}

//按名字排序
int cmp_by_name(const void* p1, const void* p2)
{
	return strcmp((((peo_info*)p1)->name), (((peo_info*)p2)->name));
}

//排序通讯录
void sort_context(context* pc)
{
	assert(pc);
	if (0 == pc->sz)
	{
		printf("通讯录为空,无法排序\n");
		return;
	}
	int input = 0;
	printf("0. 按年龄排序\n");
	printf("1. 按名字排序\n");
	printf("请选择:");
	scanf("%d", &input);
	if (input)
	{
		printf("按名字排序\n");
		qsort(pc->data, pc->sz, sizeof(pc->data[0]), cmp_by_name);
		printf("排序成功\n");
		return;
	}
	printf("按年龄排序\n");
	qsort(pc->data, pc->sz, sizeof(pc->data[0]), cmp_by_age);
	printf("排序成功\n");
}

//清空联系人
void cln_context(context* pc) 
{
	assert(pc);
	int input = 0;
	printf("确定要清空通讯录吗?\n");
	printf("1. YES\n");
	printf("0. NO\n");
	scanf("%d", &input);
	if (input)
	{
		printf("清空成功\n");
		init_context(pc);
		return;
	}
	return;
}

//销毁通讯录
void distory_context(context* pc)
{
	free(pc->data);
	pc->data = NULL;
	pc->capacity = 0;
	pc->sz = 0;
	pc = NULL;
}

//保存通讯录
void save_context(context* pc)
{
	//写数据
	//1. 打开文件
	FILE* pf = fopen("context.txt", "wb");
	if (NULL == pf)
	{
		perror("save_context::fopen");
	}
	else
	{
		//2. 写入数据
		int i = 0;
		for (i = 0; i < pc->sz; i++)
		{
			fwrite(&(pc->data[i]), sizeof(peo_info), 1, pf);
		}
		fclose(pf);
		pf = NULL;
		printf("保存成功\n");
	}
}

制作不易,点个小赞~QAQ

相关推荐
Patience to do9 分钟前
Android Studio项目(算法计算器)
android·算法·android studio
这题怎么做?!?25 分钟前
模板方法模式
开发语言·c++·算法
TeYiToKu1 小时前
笔记整理—linux驱动开发部分(1)驱动梗概
linux·c语言·arm开发·驱动开发·嵌入式硬件
DdddJMs__1352 小时前
C语言 | Leetcode C语言题解之第517题超级洗衣机
c语言·leetcode·题解
边疆.2 小时前
C++类和对象 (中)
c语言·开发语言·c++·算法
binqian2 小时前
【K8S】kubernetes-dashboard.yaml
算法·贪心算法
林浔09062 小时前
C语言部分输入输出(printf函数与scanf函数,getchar与putchar详解,使用Linux ubuntu)
c语言·开发语言
Wils0nEdwards3 小时前
Leetcode 合并 K 个升序链表
算法·leetcode·链表
Tisfy3 小时前
LeetCode 3211.生成不含相邻零的二进制字符串:二进制枚举+位运算优化
算法·leetcode·二进制·题解·枚举·位运算