fopen_s函数的一些基本的使用

fopen_s函数使用详解

我刚刚做了一个需要使用到文件操作和链表的小项目,也踩了不少坑,现在对文件操作也有了新的认知,现在分享给大家。

#fopen_s函数的简介

##函数原型

errno_t fopen_s(FILE** pFile, const char* filename, const char* mode);


##返回值

当打开失败时,返回errno_t类型的错误代码(该错误代码是可以被解析的)

当打开成功时,返回值是0,pFile变为一个有效内存地址(相当于是文件的一个代理指针),以后再对文件中的内容进行操作的时候就用这个指针。

##参数

其中,Pfile就是FILE*类型的变量的指针。

filename就是文件名。

mode就是打开方式,以下是常用的打开方式:

模式描述文件存在文件不存在文件位置
"r"只读打开成功打开失败文件开头
"w"只写清空内容创建新文件文件开头
"a"追加打开成功创建新文件文件末尾
"r+"读写打开成功打开失败文件开头
"w+"读写清空内容创建新文件文件开头
"a+"读写打开成功创建新文件文件末尾

##使用

1、数据读取

发现了没有,当我们想在不改变文件中的数据的情况下将文件中的数据写入链表时,采用“r”的方式是最好的,我现在写一个简单的打开函数:


FILE* file=NULL;
errno_t flag = 0;
flag = fopen_s(&file, DATA_FILE, "r");
//只读
//fopen_s成功返回0,失败返回错误代码
if (flag != 0)
{
	printf("打开储存文件失败\n");
	return;
}
//读取操作......

此函数是用来读取的,当我们需要逐行读取时,我们可以这样:

char line[200];
//作为一个中间值
while(fgets(line,sizeof(line),file)!=NULL)
{
    将数据存入链表......
}

fgets函数在读取到\n后会截止并自动跳到下一行,当fgets函数没读到数据时会返回值NULL,

通过这种方式我们就可以实现每一行中间值的读取。

整个的读取代码:

int num = 0;
char name[20];
int score = 0;
int count = 0;
int succes_num = 0;
int file_num = 0;
char line[100];
while (fgets(line,sizeof(line),file)!=NULL)
{
	
	if (sscanf_s(line, "学号是%d 姓名是%s 成绩是%d\n", &num, name,(unsigned)sizeof(name), &score) == 3)
	{
		struct stu_inf* p = (struct stu_inf*)malloc(sizeof(struct stu_inf));
		p->num = num;
		strcpy_s(p->name, sizeof(p->name), name);
		p->score = score;
		printf("学号是%d 姓名是%s 成绩是%d的数据读取成功\n", p->num, p->name, p->score);
		succes_num++;
		p->next = head;
		head = p;
	}
	else
	{
		printf("第%d个数据读取失败\n",count);
		file_num++;
	}
	count++;
}
if (sscanf_s(line, "学号是%d 姓名是%s 成绩是%d\n", &num, name,(unsigned)sizeof(name), &score) == 3)

这里我先读取中间值,再判断读取是否成功,成功了才分配内存。

struct stu_inf* p = (struct stu_inf*)malloc(sizeof(struct stu_inf));

这里为什么要进行内存分配呢?

  • 不知道会有多少学生

  • 每个学生的大小相同但数量不确定

  • 需要链表结构动态增长

然后我们将每一个分配了内存的节点连接起来,就实现了数据的读取。

2、数据的更新

那么,我们在将数据读取的数据进行修改后,再将修改同步到文件应该如何做呢?

此时问题就来了,我在编写的时候,因为不熟悉fopen_s的写入方式,在判定了链表中的头指针head==NULL后便直接return,这导致我无法将文件中的数据删干净。后来,我查到了问题的来源,加了一个只是使用”w“打开的操作,问题就迎刃而解了。代码如下:

if (head == NULL)
{
	errno_t result = fopen_s(file, DATA_FILE, "w");
	printf("文件已清空\n");
	fclose(file);
	return;
}

当经过操作后,链表中的数据仍然有剩余的时候,我们使用fprintf将数据写入文件:

if (fprintf(file, "学号是%d 姓名是%s 成绩是%d\n", p->num, p->name, p->score) >= 0)
{
	if (flag == 1)
	{
		printf("学号是%d,姓名是%s,成绩是%d的数据储存成功\n", p->num, p->name, p->score);
	}
	succes_num++;
}
else
{
	if (flag == 1)
	{
		printf("学号是%d,姓名是%s,成绩是%d的数据储存失败\n", p->num, p->name, p->score);
	}
	file_num++;
}

fprintf的返回值:

  • 成功: 返回写入的字符数(包括换行符等)

  • 失败: 返回负数

这里和sscanf_s的返回值是很像的,只不过sscanf_s返回的是成功读取的数据个数,fprintf返回的是成功写入的字符数罢了。

具体代码:

void save_to_file(int flag)
{
	if (DATA_FILE == NULL)
	{
		printf("文件不存在\n");
	}
	FILE* file = NULL;
	//FILE类型本来就是指针
	
	if (fopen_s(&file, DATA_FILE, "w") != 0)
	{
		printf("打开文件失败,无法储存\n");
		return;
	}
	if (head == NULL)
	{
		errno_t result = fopen_s(file, DATA_FILE, "w");
		printf("文件已清空\n");
		fclose(file);
		return;
	}
	//fuck GUET
	else 
	{
		struct stu_inf* to_delete = NULL;
		int succes_num = 0;
		int file_num = 0;
		struct stu_inf* p = head;
		while (p != NULL)
		{
			if (fprintf(file, "学号是%d 姓名是%s 成绩是%d\n", p->num, p->name, p->score) >= 0)
			{
				if (flag == 1)
				{
					printf("学号是%d,姓名是%s,成绩是%d的数据储存成功\n", p->num, p->name, p->score);
				}
				succes_num++;
			}
			else
			{
				if (flag == 1)
				{
					printf("学号是%d,姓名是%s,成绩是%d的数据储存失败\n", p->num, p->name, p->score);
				}
				file_num++;
			}
			to_delete = p;
			free(to_delete);
			p = p->next;
		}
		int total = succes_num + file_num;
		if (flag == 1)
		{
			printf("在%d人中有%d个储存成功、%d个储存失败\n", total, succes_num, file_num);
		}
		fclose(file);
		//free(file);此处不应该free,因为free是释放内存,而且之前就已经fclose过了
	}
	
	
}

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值