C-文件操作实现数据持久化,帮你快速了解文件操作函数

news2025/1/12 4:01:13

目录

一.了解文件

二.文件的打开和关闭

三.顺序读写文件函数

fputc字符输入函数

fgetc字符输入函数

 fputs文本行输出函数

 fgets文本行输入函数

fprintf格式化输出函数

fscanf格式化输入函数

fwrite二进制输出函数

fread二进制输入函数

四. 解析上述的流

 五.文件的随机读写

fseek

 ftell

rewind


一.了解文件

1.文件主要功能

  • 使用文件我们可以将数据直接存放在电脑的硬盘上,做到了数据的持久化。
  • 在以前各章所处理数据的输入输出都是以终端为对象的,即从终端的键盘输入数据,运行结果显示到显 示器上。
  • 其实有时候我们会把信息输出到磁盘上,当需要的时候再从磁盘上把数据读取到内存中使用,这里处理 的就是磁盘上文件。

2.什么是文件

磁盘上的文件是文件。

但是在程序设计中,我们一般谈的文件有两种:程序文件、数据文件(从文件功能的角度来分类的)。

2.1程序文件

包括源程序文件(后缀为.c),目标文件(windows环境后缀为.obj),可执行程序(windows环境 后缀为.exe)。

2.2数据文件

文件的内容不一定是程序,而是程序运行时读写的数据,比如程序运行需要从中读取数据的文件, 或者输出内容的文件。

 2.3 文件名

文件名包含3部分:文件路径+文件名主干+文件后缀

比如: c:\code\test.txt

二.文件的打开和关闭

以下所有讲的函数头文件都是:#include <stdio.h>

1.文件指针

一般都是通过一个FILE的指针来维护这个FILE结构的变量,这样使用起来更加方便。

我们可以创建一个FILE*的指针变量:

FILE* pf;//文件指针变量

每当打开一个文件的时候,系统会根据文件的情况自动创建一个FILE结构的变量,并填充其中的信息, 使用者不必关心细节。

例如,VS2013编译环境提供的 stdio.h 头文件中有以下的文件类型申明:

 不同的C编译器的FILE类型包含的内容不完全相同,但是大同小异。

2.文件的打开和关闭

1.打开文件函数:

代码演示: 

FILE *pf = fopen("test.txt", "w");

文件名:

文件名分为两种形式:

1.绝对路径

文件路径+文件名主干+文件后缀

2.相对路径

文件名主干+文件后缀(也可以不加后缀)

相对路劲是在当前程序文件的文件夹下,去查找

 文件的打开方式:

文件使用方式含义如果指定文件不存在
“r”(只读)为了输入数据,打开一个已经存在的文本文件出错
“w”(只写)为了输出数据,打开一个文本文件建立一个新的文件
“a”(追加)向文本文件尾添加数据建立一个新的文件
“rb”(只读)为了输入数据,打开一个二进制文件出错
“wb”(只写)为了输出数据,打开一个二进制文件建立一个新的文件
“ab”(追加)向一个二进制文件尾添加数据出错
“r+”(读写)为了读和写,打开一个文本文件出错
“w+”(读写)为了读和写,建议一个新的文件建立一个新的文件
“a+”(读写)打开一个文件,在文件尾进行读写建立一个新的文件
“rb+”(读写)为了读和写打开一个二进制文件出错
“wb+”(读写)为了读和写,新建一个新的二进制文件建立一个新的文件
“ab+”(读写)打开一个二进制文件,在文件尾进行读和写建立一个新的文件

返回:

正确代码书写:

//打开文件
	FILE *pf = fopen("test.txt", "w");
	//文件是有可能打开失败的,文件名出错,打开方式问题等
	if (NULL == pf)
	{
		perror("fopen");
		return;
	}

只有打开文件就一定要搭配上判断

2.关闭文件函数

代码演示: 

fclose(pf);

正确的代码规范:

int main()
{
	//打开文件
	FILE *pf = fopen("test.txt", "w");
	//文件是有可能打开失败的,文件名出错,打开方式问题等
	if (NULL == pf)
	{
		perror("fopen");
		return;
	}

	//写文件
	//……

	//关闭文件
	fclose(pf);
	pf = NULL;//防止再次使用此指针

	return 0;
}

三.顺序读写文件函数

  • 这里的输入是指把文件的数据输入到程序内存中
  • 输出指的是内存中的数据,输出到文件中

站在程序内存的角度,把文件想成平时打印的cmd黑框就好

功能函数名适用于
字符输入函数fgetc所有输入流
字符输出函数fputc所有输出流
文本行输入函数fgets所有输入流
文本行输出函数fputs所有输出流
格式化输入函数fscanf所有输入流
格式化输出函数fprintf所有输出流
二进制输入fread文件
二进制输出fwrite文件

fputc字符输入函数

函数原型:

补充:输入流是什么 后面讲现在你们看一下代码就懂

函数代码: 

这是我当前文件下的一些文件,我讲利用打开方式自动创建一个文件

运行程序前的文件夹:

 代码:

#include<stdio.h>
int main()
{
	//打开文件
	FILE* pf = fopen("test.txt", "w");
	if (NULL == pf)
	{
		perror("fopen");
		return 1;
	}
	//写文件
	int i = 0;
	for (i = 0; i < 26; i++)
	{
		fputc('a' + i, pf);//写入26个字母
	}
	
	//关闭文件
	fclose(pf);
	pf = NULL;

	return 0;
}

运行程序前的文件夹:

你们可以去看看是不是跟我打开的文件夹名相同,而且已经在里面写入了26个字母:

返回:

函数正常执行返回所写数据,字符返回对应ASII码值

发生写入错误返回EOF

fgetc字符输入函数

函数原型

返回:

函数正常执行返回所写数据,字符返回对应ASII码值

发生写入错误返回EOF

代码:

我会读取刚刚fgetc输入到文件中的数据

注意:我打开方式的变化

#include<stdio.h>
int main()
{
	//打开文件
	FILE* pf = fopen("test.txt", "r");
	if (NULL == pf)
	{
		perror("fopen");
		return 1;
	}

	//读文件
	int ch;
	while ((ch = fgetc(pf)) != EOF)
	{
		printf("%c ", ch);
	}

	//关闭文件
	fclose(pf);
	pf = NULL;

	return 0;
}

fgetc读取了一个字符会自动向后移动一位

结果:

 fputs文本行输出函数

函数原型:

 返回:

代码:

一次输出一行

#include<stdio.h>
int main()
{
	//打开文件
	FILE* pf = fopen("test.txt", "w");
	if (NULL == pf)
	{
		perror("fopen");
		return 1;
	}
	//写文件
	fputs("hallo\n", pf);
	fputs("word", pf);
	
	//关闭文件
	fclose(pf);
	pf = NULL;

	return 0;
}

结果:

 有此可见转意字符\n等也是可以操作的

补充:因为文件方式的原因会把之前的数据覆盖掉,成为新的数据如果想不覆盖要用追加的方式打开,我现在把打开方式改为追加执行

#include<stdio.h>
int main()
{
	//打开文件
	FILE* pf = fopen("test.txt", "a");//注意我把打开方式改为了追加a
	if (NULL == pf)
	{
		perror("fopen");
		return 1;
	}
	//写文件
	fputs("hallo\n", pf);
	fputs("word", pf);
	
	//关闭文件
	fclose(pf);
	pf = NULL;

	return 0;
}

结果:

 还有一个二进制的追加ab,其余打开方式请自行去查看上面的表格

 fgets文本行输入函数

函数原型:

 返回:

代码:

一次输入一行

#include<stdio.h>
int main()
{
	//打开文件
	FILE* pf = fopen("test.txt", "r");
	if (NULL == pf)
	{
		perror("fopen");
		return 1;
	}
	//读文件
	char arr[] = "#######################";//用来观察一下的字符串

	fgets(arr, 20, pf);
	printf("%s", arr);//注意我这里没有加\n因为之前的输入里面是输入进去了\n的
	fgets(arr, 20, pf);
	printf("%s", arr);


	//关闭文件
	fclose(pf);
	pf = NULL;

	return 0;
}

注意我这里没有加\n因为之前的输入里面是输入进去了\n的

结果:

fprintf格式化输出函数

函数原型:

 可以发现只是多了一个参数其余并没有变化

返回:

代码:

格式化输出数据到文件中

#include<stdio.h>
struct S
{
	char name[20];
	int age;
	float scores;
};

int main()
{
	//打开文件
	struct S s = { "Laoli" ,20 ,95.5f };

	FILE* pf = fopen("test.txt", "w");
	if (NULL == pf)
	{
		perror("fopen");
		return 1;
	}
	//写文件
	fprintf(pf, "%s %d %f\n", s.name, s.age, s.scores);


	//关闭文件
	fclose(pf);
	pf = NULL;

	return 0;
}

这个字符在输出字符串时遇到空格也会正常输出

结果:

fscanf格式化输入函数


函数原型: 

 返回:

代码:

把刚刚放进文件的数据格式化拿出来

#include<stdio.h>
struct S
{
	char name[20];
	int age;
	float scores;

};

int main()
{
	//打开文件
	struct S s = { 0 };
	FILE* pf = fopen("test.txt", "r");
	if (NULL == pf)
	{
		perror("fopen");
		return 1;
	}
	//读文件
	fscanf(pf, "%s %d %f", s.name, &(s.age), &(s.scores));
	printf("%s %d %f", s.name, s.age, s.scores);

	//关闭文件
	fclose(pf);
	pf = NULL;

	return 0;
}

结果:

这个函数在遇到空格会停止输入所有项,例如在Laoli中间加上空格:Lao li

fwrite二进制输出函数

函数原型: 

 

这个函数是以二进制的方式进行输出的

 返回:

 代码:

#include<stdio.h>
struct S
{
	char name[20];
	int age;
	float scores;

};

int main()
{
	//打开文件
	struct S s = { "Laoli" ,20 ,95.5f };

	FILE* pf = fopen("test.txt", "wb");//注意我已经改变了文件的打卡方式
	if (NULL == pf)
	{
		perror("fopen");
		return 1;
	}
	//写文件
	fwrite(&s, sizeof(struct S), 2, pf);

	//关闭文件
	fclose(pf);
	pf = NULL;

	return

注意我已经改变了文件的打卡方式

结果:

大家可以看到除了字符串什么都看不懂呀,这个烫烫烫烫烫烫是什么鬼呀,其实是因为二进制的形式存储的,计算机可以看懂就可以了,也可以利用fread函数查看内容

fread二进制输入函数

函数原型:

返回:

代码:

读取刚刚存入文件的数据,以二进制形式读取

#include<stdio.h>
struct S
{
	char name[20];
	int age;
	float scores;

};

int main()
{
	//打开文件
	struct S s = { 0 };

	FILE* pf = fopen("test.txt", "rb");
	if (NULL == pf)
	{
		perror("fopen");
		return 1;
	}
	//读文件
	fread(&s, sizeof(struct S), 1, pf);
	printf("%s %d %f", s.name, s.age, s.scores);


	//关闭文件
	fclose(pf);
	pf = NULL;

	return 0;
}

结果:

 

四. 解析上述的流

以上函数都是在文件流中拿信息,是需要fopen函数来打开的文件流

还几个默认打开的流:

 代码:

 五.文件的随机读写

其实这些函数也并不是随机的,也是有规律的,但不再是从开头到结尾了

fseek

函数原型:

偏移量(字节为单位): 

向右移动用正数,向左移动用负数

 起始位置设置:

 返回:

代码:

我手动的在文件中添加这样的数据:

从末尾移动三位取出数据:

#include<stdio.h>

int main()
{
	//打开文件
	FILE* pf = fopen("test.txt", "rb");
	if (NULL == pf)
	{
		perror("fopen");
		return 1;
	}

	fseek(pf, -3, SEEK_END);
	int ch = fgetc(pf);
	printf("%c\n", ch);

	//关闭文件
	fclose(pf);
	pf = NULL;

	return 0;
}

 ftell

功能:返回文件指针相对于起始位置的偏移量

 函数原型:

返回: 

成功返回当前位置

 

 代码:

我们就用刚刚的代码加上函数试一下:

#include<stdio.h>

int main()
{
	//打开文件
	FILE* pf = fopen("test.txt", "rb");
	if (NULL == pf)
	{
		perror("fopen");
		return 1;
	}

	fseek(pf, -3, SEEK_END);
	int ch = fgetc(pf);
	printf("%c\n", ch);
	int pos = ftell(pf);
	printf("%d", pos);

	//关闭文件
	fclose(pf);
	pf = NULL;

	return 0;
}

结果:

分析:

rewind

功能:让文件指针的位置回到文件的起始位置

函数原型: 

 

代码:

#include<stdio.h>

int main()
{
	//打开文件
	FILE* pf = fopen("test.txt", "rb");
	if (NULL == pf)
	{
		perror("fopen");
		return 1;
	}

	fseek(pf, -3, SEEK_END);
	int ch = fgetc(pf);
	printf("%c\n", ch);

	rewind(pf);//回到文件的起始位置
	int pos = ftell(pf);
	printf("%d", pos);

	//关闭文件
	fclose(pf);
	pf = NULL;

	return 0;
}

结果:

这个函数非常简单不做过多介绍了

 此片文章设计大量函数,记不住很正常,收藏一波需要的时候来查一查。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/299.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Redis 主从安装-Centos

Redis 主从安装-Centos 由于机器有限&#xff0c;所以接下来的教程都是在一台虚拟机中进行部署安装. Redis主从工作原理 如果你为master配置了一个slave&#xff0c;不管这个slave是否是第一次连接上Master&#xff0c;它都会发送一个PSYNC命令给master请求复制数据。master…

计算机网络--传输层

这篇博客博主应该在前天就要完成的&#xff0c;但是博主忙乱了&#xff0c;又堕落几天&#xff0c;希望大家别像我一样最近学习三天打鱼&#xff0c;两个天晒网的。此后博主为了激励自己重头再来&#xff0c;就特意换了个发型&#xff0c;哈哈。回到正题&#xff0c;传输层也是…

操作系统真相还原_第4章:进入保护模式

文章目录实模式的缺陷保护模式的扩展段寄存器的变化寄存器扩展寻址扩展全局描述符表GDT描述符格式字段含义进入保护模式步骤解释示例说明程序编写boot.incmbr.sloader.s编译并写入硬盘启动bochs执行实模式的缺陷 1、实模式下用户程序所引用的地址都是指向真实的物理地址&#…

计算机等级考试Python二级

补记录一下之前考Python二级的一些相关理论记录 数据结构与算法 算法杂度 算法复杂度用来衡量算法的优劣&#xff0c;它包括算法的时间复杂度和算法的空间复杂度 时间复杂度&#xff1a;执行算法所需要的计算量【所需要的计算工作量是用算法所执行的基本运算次数来度量的】 …

子串和子序列问题-动态规划向

1. 子串子序列问题概述 有关于子序列和子串的问题是字符串或者数组经常会遇到的问题&#xff0c;一般我们经常使用多指针&#xff0c;滑动窗口&#xff0c;回溯&#xff0c;动态规划的方式去解决&#xff0c;而本篇重点关注能用动态规划解决或者说明显使用动态规划解决的子串问…

Java开发手册解析_编程规约-集合处理

前言 《Java开发手册&#xff08;黄山版&#xff09;》编程规约-集合处理 该章节的知识点基本都来源于jdk源码&#xff0c;将结合源码及例子进行理解 备注&#xff1a;文章中的详细及说明为手册本身内容 博客地址&#xff1a;芒果橙的个人博客 【http://mangocheng.com】 1.【强…

服务与发现

文章目录服务与发现什么是服务发现应用层服务发现模式平台层服务发现模式服务与发现 假设你正在编写一些调用具有 REST API 的服务的代码&#xff0c;为了发出请求&#xff0c;你的代码需要知道服务实例的网络位置&#xff08;IP 地址和端口&#xff09;&#xff0c;在物理硬件…

整型数据是如何在内存中存储的

&#x1f3d6;️作者&#xff1a;malloc不出对象 ⛺专栏&#xff1a;《初识C语言》 &#x1f466;个人简介&#xff1a;一名双非本科院校大二在读的科班编程菜鸟&#xff0c;努力编程只为赶上各位大佬的步伐&#x1f648;&#x1f648; 目录前言一. 整型在内存中的存储1.1 整型…

Vue2生命周期详细图解和代码

加油&#xff0c;新时代打工人&#xff01;&#xff01;&#xff01; 话不多说&#xff0c;看图。 <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><meta http-equiv"X-UA-Compatible" content"…

C语言数据结构——链表

C语言数据结构——链表 链表包括单链表&#xff0c;双链表&#xff0c;循环链表等。 而今天要说的是单链表&#xff0c;它是一个线性表&#xff0c;它在内存中是无序的&#xff0c;由一个个指针来连接。 图示&#xff1a; 小方块代表的就是存储的数据&#xff0c;箭头就是指…

(46)STM32——FATFS文件系统实验

目录 学习目标 运行结果 文件系统 常用系统 FATFS 特点 结构图 移植步骤 disk_initialize disk_status disk_read disk_write disk_ioctl get_fattime 代码 总结 学习目标 我们要来介绍的是FATFS文件系统&#xff0c;这是一个为嵌入式设计的文件系统&#xff0c…

大学科目网课搜题接口

大学科目网课搜题接口 本平台优点&#xff1a; 多题库查题、独立后台、响应速度快、全网平台可查、功能最全&#xff01; 1.想要给自己的公众号获得查题接口&#xff0c;只需要两步&#xff01; 2.题库&#xff1a; 查题校园题库&#xff1a;查题校园题库后台&#xff08;点…

【1024社区大奖】让你一小时内狂揽大奖[保姆级教程①]

四层挑战&#xff0c;一小时内拿捏&#xff01;&#xff08;上&#xff09;一、龙蜥社区大奖二、战前准备1.注册码云Gitee2.注册龙蜥社区三、开始挑战&#xff0c;包揽大奖&#xff01;①第一层&#xff1a;小龙推荐 [15分钟]②第二层随机试炼 [15分钟]一、龙蜥社区大奖 活动分…

【论文笔记】Transformer-based deep imitation learning for dual-arm robot manipulation

【论文笔记】Transformer-based deep imitation learning for dual-arm robot manipulation Abstract 问题&#xff1a;In a dual-arm manipulation setup, the increased number of state dimensions caused by the additional robot manipulators causes distractions and …

微信小程序入门与实战之更多电影列表与电影搜索

wx.request的更多参数详解 在网络请求中我们可以采用下面这种形式&#xff1a; 如果我们可以不采用直接写在url的方式我们可以采用data的方式&#xff1a; 默认请求方式是GET我们可以通过设置method修改请求方式&#xff1a; 更多电影页面 我们要实现的效果&#xff1a;…

应用层——HTTP协议

文章目录一、应用层1.1 应用层概念1.2 再谈协议二、网络版本的计算器网络计算器编码部分版本1&#xff1a;原生版本版本2&#xff1a;引入序列化和反序列化三、HTTP协议3.1 URL3.2 urlencode和urldecode3.3 HTTP协议格式3.3.1 请求报文3.3.2 响应报文3.4 HTTPDemo3.4.1改进3.4.…

这里不适合做技术

6点&#xff0c;の&#xff0c;下班了又是一个差不多一样的星期过去了&#xff0c;又是一个差不多的周末要到来了。我也差不多要离开这家公司了&#xff0c;入职4年多&#xff0c;那时候雄心壮志&#xff0c;决定干一番大事业&#xff0c;那个时候的自己&#xff0c;技术的炉火…

【图像融合】基于 DCT结合拉普拉斯金字塔的图像融合附matlab代码

✅作者简介&#xff1a;热爱科研的Matlab仿真开发者&#xff0c;修心和技术同步精进&#xff0c;matlab项目合作可私信。 &#x1f34e;个人主页&#xff1a;Matlab科研工作室 &#x1f34a;个人信条&#xff1a;格物致知。 更多Matlab仿真内容点击&#x1f447; 智能优化算法 …

论文理解与笔记【CVPR_2022.6】Region-Aware Face Swapping

论文理解与笔记【CVPR_2022】Region-Aware Face Swapping论文的缩写全拼&#xff1a;一、贡献二、介绍三、提出问题&#xff0c;也是论文解决的问题四、具体实现方案五、实验六、最终感想和总结论文地址&#xff1a;传送门或者传送门2 先看看效果&#xff1a; 论文的缩写全拼…

【单片机毕业设计】【mcuclub-jj-003】基于单片机的八层电梯的设计

最近设计了一个项目基于单片机的八层电梯系统&#xff0c;与大家分享一下&#xff1a; 一、基本介绍 项目名&#xff1a;八层电梯 项目编号&#xff1a;mcuclub-jj-003 单片机类型&#xff1a;STC89C52、STM32F103C8T6 功能简介&#xff1a; 1、通过3*4矩阵键盘实现电梯内部…