【开发细节】用C语言基础写学生管理系统(五)

前情回顾


自定义preconf.hkernel_list.hsysbrowse三个头文件,完成了核心头文件前的预配置、核心头文件的操作、信息浏览系统的功能。

一、本次目标


构建文件数据流读写的相关操作,便于保存学生信息表、系统的设置(存储路径、控制台颜色等)

图片名称 GitHub:https://github.com/ITchujian/StudentManagementSystem_2022_C

注:为方便分享本次开发的经历,我把分析过程以及代码书写过程,以文字、图片形式合计放于开发记录中,但是一些非常基础的行为动作我将不会讲解或者阐述。
当前位置:【开发细节】用C语言基础写学生管理系统(五)
可跳转:

二、开发记录


步骤1

老规矩,创建一个名为sysdoc.h的头文件,并包含一下自定义的头文件kernel_list.h

#include "kernel_list.h"

然后,我们将在当前运行的文件夹下创建一个名为SMSdir的文件夹,用于存储学生信息表、系统设置。

步骤2

创建一个名为createFolder的函数,它的作用:创建多级目录。

Status createFolder(char* path)
{
	char folder_path[128];
	sprintf(folder_path, "mkdir %s", path);
	if (_access(path, 0) == -1)
	{
		system(folder_path);
	}
	return OK;
}

步骤3

面临的一大问题,如何存储我们的数据和结构体呢,那不妨用数据流二进制吧。
写入二进制流:

Status writeFile(char* path, void* struct_s, int s_size, int length)
{
	FILE* fp;
	fopen_s(&fp, path, "wb+");
	if (fp != 0)
	{
		fwrite(struct_s, s_size, length, fp);
		fclose(fp);
		return OK;
	}
	else
		return INFEASIBLE;
}

读取二进制流:

Status readFile(char* path, void* struct_s, int s_size, int length)
{
	FILE* fp;
	fopen_s(&fp, path, "rb+");
	if (fp != 0)
	{
		fread(struct_s, s_size, length, fp);
		fclose(fp);
		return OK;
	}
	else
		return INFEASIBLE;
}

步骤4

我们需要哪些,学生们都在ElemType结构体中,所以我们应该存储这个结构体,不妨将这个文件命名为:students.bin。系统设置放在:config.bin,它是最先加载的,它将加载students.bin的存储路径、备份路径、以及控制台颜色值,那就有人纳闷了,我在preconf.h中明明是这样定义的:

typedef struct
{
	char file_path[128];
	char backup_path[128];
	char list_path[128];
	char sys_color[32];
} SysConfig;
SysConfig config_bin = {};

backup_path还好理解,备份路径,那list_path是个什么鬼?
list_path当然就是存储SqList结构体的存储路径啦,解释一下为何要这个存储路径:

如果我们的项目是这样运行:加载config.bin→加载students.bin→控制台输出菜单,然后就是根据用户操作,假设我们做浏览所有学生信息的操作,该函数是如此定义的:

Status putAllList(SqList* L)
{
	int i = 0;
	printf("┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓\n");
	printf("┃  姓名        学号        性别        年龄        语文        数学        英语        平均分        总分   ┃\n");
	printf("┣━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┫\n");
	while (i < L->length)
	{
		printf("┃  %-9s%-16d%-12s%-11d%-12.2f%-12.2f%-12.2f%-13.2f%-8.2f┃\n", (L->elem[i]).name, (L->elem[i]).num, (L->elem[i]).sex, (L->elem[i]).age, (L->elem[i]).score_literature, (L->elem[i]).score_math, (L->elem[i]).score_english, (L->elem[i]).average_score, (L->elem[i]).sum_score);
		++i;
	}
	printf("┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛\n");
	return OK;
}

也就是说,如果我们按照上述方式运行,我们的L->length仅仅被InitList(SqList* L)初始化了,它对应的值是0,而我们后续的行为操作、功能实现,都是要基于这个值的,无论你如何加载,尽管students.bin文件存储了上万条学生的信息,依然打印不出一条的,千万记得,我们的核心是线性表SqList,脱离了其中的变量是不可行的。所以,我们优化一下我们的运行逻辑:

加载config.bin→加载list_path.bin→加载students.bin→控制台输出菜单→用户操作

现在才是正确的逻辑,否则你永远操作的是0长度的线性表,毫无意义。
以上是我开发项目时忽略的问题,打上断点后,才发现的L->length一直是0,真的是太大意了😒。

步骤5

依次编写上述的加载方法。

Status loadConfig(void)
{
	char dir_path[] = ".\\SMSdir";
	createFolder(dir_path);
	char config_path[128];
	sprintf(config_path, "%s\\config.bin", dir_path);
	readFile(config_path, &config_bin, sizeof(SysConfig), 4);
	system(config_bin.sys_color);
	return OK;
}

然后是加载list_path.bin

Status loadList(SqList* L)
{
	readFile(config_bin.list_path, L, sizeof(SqList), 3);
	return OK;
}

最后是加载students.bin

Status loadStu(SqList* L)
{
	readFile(config_bin.file_path, L->elem, sizeof(ElemType), L->length);
	return OK;
}

sysdoc.hの完整代码:

#pragma once
/*********************************************************************
 * 转载请注明来源/Reprint please indicate the source
 * @FileName sysdoc.h
 * @Description 文件读写操作相关文件/File read and write operations related files
 * @History
 * version      author      data       introduction and operations
 *  1.0         初见     2022-01-23             Create
 *  ***         ***      ****-**-**             *******
 */

#include "kernel_list.h"
 /*********************************************************************
  * @chujian(cn) 引入自定义头文件
  * @chujian(en) Import custom header files
  */

Status setMenu(void)
{
	printf("┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓\n");
	printf("┃                            【副】系 统 设 置                                  ┃\n");
	printf("┣━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┫\n");
	printf("┃                 警告 通常情况下,我并不建议您更改除3以外的设置                ┃\n");
	printf("┃请选择操作:                                                                    ┃\n");
	printf("┃                             1 > 更改存储路径                                  ┃\n");
	printf("┃                             2 > 更改备份路径                                  ┃\n");
	printf("┃                             3 > 设置前背景颜色                                ┃\n");
	printf("┃                             4 > [危]内核列表路径                              ┃\n");
	printf("┃                             0 > 返回主系统                                    ┃\n");
	printf("┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛\n");
	printf("\nINPUT:");
	return OK;
}
/*********************************************************************
 * @chujian(cn) 系统设置界面
 * @chujian(en) System setting interface
 */

Status colorMenu(void)
{
	printf("颜色参考表:\n");
	printf("0 = 黑色       8 = 灰色\n");
	printf("1 = 蓝色       9 = 淡蓝色\n");
	printf("2 = 绿色       A = 淡绿色\n");
	printf("3 = 浅绿色     B = 淡浅绿色\n");
	printf("4 = 红色       C = 淡红色\n");
	printf("5 = 紫色       D = 淡紫色\n");
	printf("6 = 黄色       E = 淡黄色\n");
	printf("7 = 白色       F = 亮白色\n");
	return OK;
}
/*********************************************************************
 * @chujian(cn) 对应系统设置中的第三项
 * @chujian(en) Corresponds to the third item in the system settings
 */

Status createFolder(char* path)
{
	char folder_path[128];
	sprintf(folder_path, "mkdir %s", path);
	if (_access(path, 0) == -1)
	{
		system(folder_path);
	}
	return OK;
}
/*********************************************************************
 * @chujian(cn) 创建目录
 * @chujian(en) Create a directory
 */

Status writeFile(char* path, void* struct_s, int s_size, int length)
{
	FILE* fp;
	fopen_s(&fp, path, "wb+");
	if (fp != 0)
	{
		fwrite(struct_s, s_size, length, fp);
		fclose(fp);
		return OK;
	}
	else
		return INFEASIBLE;
}
/*********************************************************************
 * @chujian(cn) 将数据流写入.bin文件
 * @chujian(en) Write data stream to .bin file
 */

Status readFile(char* path, void* struct_s, int s_size, int length)
{
	FILE* fp;
	fopen_s(&fp, path, "rb+");
	if (fp != 0)
	{
		fread(struct_s, s_size, length, fp);
		fclose(fp);
		return OK;
	}
	else
		return INFEASIBLE;
}
/*********************************************************************
 * @chujian(cn) 从.bin文件中读取数据流
 * @chujian(en) Read data stream from .bin file
 */

Status loadConfig(void)
{
	char dir_path[] = ".\\SMSdir";
	createFolder(dir_path);
	char config_path[128];
	sprintf(config_path, "%s\\config.bin", dir_path);
	readFile(config_path, &config_bin, sizeof(SysConfig), 4);
	system(config_bin.sys_color);
	return OK;
}
/*********************************************************************
 * @chujian(cn) 初始化配置config.bin文件
 * @chujian(en) Initialize the configuration config.bin file
 */

Status loadList(SqList* L)
{
	readFile(config_bin.list_path, L, sizeof(SqList), 3);
	return OK;
}
/*********************************************************************
 * @chujian(cn) 加载内核线性表中除对应elem的数据
 * @chujian(en) Load the data in the kernel linear table except the student structure
 */

Status loadStu(SqList* L)
{
	readFile(config_bin.file_path, L->elem, sizeof(ElemType), L->length);
	return OK;
}
/*********************************************************************
 * @chujian(cn) 加载上一次保存的学生信息表
 * @chujian(en) Load the last saved student information sheet
 */

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

顾平安6

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值