C语言文件操作【基础知识 + 顺序读写 + 文件版通讯录】

news2024/11/15 17:15:36

全文目录

  • 😀 前言
  • 🤔 什么是文件
    • 😶 程序文件
    • 😶 数据文件
    • 😶 文件名
  • 🤨 文件指针
  • 🤫 文件的打开和关闭
    • 😑 `fopen` 打开文件
      • 📙 **mod的规律:**
    • 😑 `fclose` 关闭文件
      • 📙 文件打开不关闭的后果
  • 😵‍💫 文件的顺序读写
    • 🙄 **`fputc` 字符输出函数**
    • 🙄 **`fgetc` 字符输入函数**
    • 🙄 `fputs` 文本行输出函数
    • 🙄 **`fgets` 文本行输入函数**
    • 🙄 `fprintf` 格式化输出函数
    • 🙄 `fscanf` 格式化输入函数
    • 🙄 `fwrite` 二进制输出函数
    • 🙄 `fread` 二进制输入函数
  • 😏 三组 `scanf` 和 `printf` 函数对比
  • 😍 文件版通讯录
    • 🙂 将通讯录信息保存在文件中
    • 🙂 加载文件中的通讯录信息
  • 🌈 总结

😀 前言

前面写的程序都是一闪即逝,只要关闭了程序,就找不到运行的结果。如果想要将运行的结果保存下来,下次运行的时候接着上次运行,只有自己想要删除数据,数据才会消失。这就涉及到了数据持久化的问题, 我们一般数据持久化的方法有,把数据存放在磁盘文件、存放到数据库等方式。

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

🤔 什么是文件

文件是计算机文件属于文件的一种,与普通文件载体不同,计算机文件是以计算机硬盘为载体存储在计算机上的信息集合。文件可以是文本文档、图片、程序等等。文件通常具有三个字母的文件扩展名,用于指示文件类型(例如,图片文件常常以 JPEG 格式保存并且文件扩展名为 .jpg)。

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

😶 程序文件

程序文件存储的是程序,包括源程序和可执行程序。

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

😶 数据文件

数据文件比较多,数据的概念也比较广泛图形图像声音数字各种码制都是数据,存储这些数据的文件就是数据文件。

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

本文就是来学习一下数据文件。

以前我们写的代码所处理数据的输入输出都是以终端为对象的,即从终端的键盘输入数据,运行结果显示到显示器上。

但是有时候我们会把信息输出到磁盘上,当需要的时候再从磁盘上把数据读取到内存中使用,这里处理的就是磁盘上的文件。

在这里插入图片描述

😶 文件名

一个文件要有一个唯一的文件标识,以便用户识别和引用。

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

例如:c:\code\test.txt

为了方便起见,文件标识常被称为文件名

🤨 文件指针

文件类型指针简称文件指针

所谓的文件类型其实就是一个结构体类型:

每个被使用的文件都在内存中开辟了一个相应的文件信息区,用来存放文件的相关信息(如文件的名字,文件状态及文件当前的位置等)。这些信息是保存在一个结构体变量中的。该结构体类型是有系统声明的,取名FILE.

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

其中在VS2013提供的stdio.h中,文件类型的声明如下:

struct _iobuf 
{
	char *_ptr;
	int _cnt;
	char *_base;
	int _flag;
	int _file;
	int _charbuf;
	int _bufsiz;
	char *_tmpfname;
};
typedef struct _iobuf FILE;

在这里插入图片描述

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

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

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

定义pf是一个指向FILE类型数据的指针变量。可以使pf指向某个文件的文件信息区(是一个结构体变量)。通过该文件信息区中的信息就能够访问该文件。也就是说,通过文件指针变量能够找到与它关联的文件。

在这里插入图片描述

🤫 文件的打开和关闭

使用文件之前需要打开文件,使用完要关闭文件(这个很重要,后面说)。

ANSIC 规定使用fopen函数来打开文件,fclose来关闭文件。

😑 fopen 打开文件

函数描述:
在这里插入图片描述

filename:文件名

文件名(路径 + 文件名)。如果没有指定路径,默认是在当前源文件的路径下(相对路径)。
注意: 路径的 \字符需要转义:\\

mod:打开文件的方式

在这里插入图片描述

📙 mod的规律:

文件不存在时:

如果是w都是创建新的文件,r都是出错,a 除了ab 都是创建新文件

文件存在时:

如果文件存在并且只是以w的形式打开文件(包括wb)。文件的内容会被清空

双重形态

读带上 + 就是读写, 追加和写带上 + 就是读写,否则都只能读或者写。

返回值 Return Value

如果文件被成功打开,函数将返回一个指向file对象的指针。

否则,将返回一个空指针。

在大多数库实现中,errno变量也设置为失败时的系统特定错误代码。

😑 fclose 关闭文件

函数描述:

在这里插入图片描述

关闭文件流stream

返回值Return Value

如果成功了返回0。

失败返回EOF

// demo
fclose(pf);
pf = NULL;

📙 文件打开不关闭的后果

1. 如果不关闭文件,可能会导致文件临时数据丢失,造成文件写入失败。因为文件数据在关闭之前不保存在磁盘,而是保存在运行内存中,关闭或者主动刷新才写入磁盘。

2. 还有文件没有关闭,会浪费系统的文件描述符的分配。

😵‍💫 文件的顺序读写

输出就是程序向文件里面写数据, 输入就是程序从文件里面读数据。读(输入)写(输出)都是以程序为参照物

顺序读写就是以文件从前往后依次读或写。

顺序读写函数:

在这里插入图片描述

适应所有输入流的函数,只需要将文件指针改为标准输入输出就可以实现标准的输入输出了。

🙄 fputc 字符输出函数

函数描述:

在这里插入图片描述

将字符character写入steam 指向的文件中。

返回值Return Value

写入成功返回被写入的字符。

写入失败返回EOF,并且设置错误码 。

// demo
for (char ch = 'a'; ch <= 'z'; ch++)
{
	fputc(ch, pf);
}

🙄 fgetc 字符输入函数

函数描述:

在这里插入图片描述

steam 指向的文件中读取一个字符。

返回值 Return Value

如果成功读取返回读取字符的ASCII码值。

如果读取到文件的末尾,返回EOF,并且为 steam 设置eof (end of file)

如果发生阅读错误同样返回EOF,但是会改为设置错误码。

// demo
char ch;
while ((ch = fgetc(pf)) != EOF)
{
	printf("%c", ch);
}

🙄 fputs 文本行输出函数

函数描述:

在这里插入图片描述

将字符串 str 输出到 steam指向的文件中。

返回值 Return Value

成功时,将返回非负值。

出错时,该函数返回 EOF 并设置错误指示器(ferror)。

// demo
fputs("qwertyuiop", pf); 	// 注意该函数不会主动添加\n

🙄 fgets 文本行输入函数

函数描述:

在这里插入图片描述

steam 指向的文件中读取字符并将其作为 C 字符串存储到 str中,直到读取 (num-1) 个字符或到达换行符或文件末尾,以先发生者为准。

返回值Return Value

成功后,函数返回 str

如果在尝试读取字符时遇到文件末尾,则设置 eof 指示器 (feof)。如果在读取任何字符之前发生这种情况,则返回的指针为空指针(str 的内容保持不变)。

如果发生读取错误,则设置错误指示器(ferror),并返回空指针(但str指向的内容可能已更改)。

// demo 
char str[256];
fgets(str, 256, pf);
printf("%s", str);

🙄 fprintf 格式化输出函数

函数描述:

在这里插入图片描述

将按格式指向流的 C 字符串写入流。如果 format 包含格式说明符(以 % 开头的子序列),则格式后面的其他参数将被格式化并插入到生成的字符串中,替换其各自的说明符。

format 参数之后,函数至少需要与格式指定的一样多的其他参数。

返回值Return Value

成功后,将返回写入的字符总数。

如果发生写入错误,则设置错误指示器(ferror)并返回负数。

如果在写入宽字符时发生多字节字符编码错误,errno 将设置为 EILSEQ 并返回负数。

文档中对于fprintf 的介绍巴拉巴拉一大堆,看着就头大。我们可以对比一下printf

在这里插入图片描述
可以看到 fprintf 对于 printf 只多了一个文件指针,所以使用fprintf 只需要比printf 多传一个文件指针就行了。

// demo
struct Student
{
	char name[10];
	int age;
	char phone[12];
} s = { "张三", 19, "1008611" };

fprintf(pf, "%s %d %s", s.name, s.age, s.phone);

🙄 fscanf 格式化输入函数

函数描述:

在这里插入图片描述

从流中读取数据,并根据参数格式将其存储到附加参数所指向的位置。

附加参数应指向已分配的对象,该对象的类型由格式字符串中相应的格式说明符指定。

返回值Return Value :

成功后,函数将返回成功填充的参数列表中的项数。此计数可能与预期的项数匹配,也可能由于匹配失败、读取错误或到达文件末尾而减少(甚至为零)。

如果在读取时发生读取错误或到达文件末尾,则会设置正确的指示器(feof或ferror)。

并且,如果在成功读取任何数据之前发生任何一种情况,则返回EOF
如果在解释宽字符时发生编码错误,函数会将errno设置为EILSEQ

同样的对比scanf

在这里插入图片描述

结果一目了然,只需要在使用scanf 的基础上加上一个文件指针就行了。

// demo
struct Student
{
	char name[10];
	int age;
	char phone[12];
} s;

fscanf(pf, "%s%d%s", &s.name, &s.age, &s.phone);

printf("%s %d %s\n", s.name, s.age, s.phone);

🙄 fwrite 二进制输出函数

函数描述:

在这里插入图片描述

从ptr指向的内存块向流stream中的当前位置写入count个元素的数组,每个元素的大小为size字节。

流的位置指示符提前写入的字节总数。

在内部,该函数将ptr指向的块解释为无符号char类型的(size*count)元素数组,并将它们按顺序写入流,就像为每个字节调用fputc一样。

返回值 Return Value :

返回成功写入的元素总数。

如果此数字与计数参数不同,则写入错误会阻止函数完成。在这种情况下,将为流设置错误指示器(ferror)。

如果大小或计数为零,则函数返回零,并且错误指示器保持不变。

// demo
struct Student
{
	char name[10];
	int age;
	char phone[12];
} s = { "张三", 19, "1008611" };

fwrite(&s, sizeof(s), 1, pf);

🙄 fread 二进制输入函数

函数描述:

在这里插入图片描述

从流中读取count个元素的数组,每个元素的大小为size字节,并将它们存储在ptr指定的内存块中。

流的位置指示符提前读取的字节总数。

如果成功,读取的字节总数为(size*conut)。

返回值Return Value

返回成功读取的元素总数。

如果此数字与count参数不同,则表示发生读取错误,或者读取时已到达文件末尾。在这两种情况下,都设置了适当的指示器,可以分别用ferrorfeof进行检查。

如果大小或计数为零,则函数返回零,并且ptr所指向的流状态和内容保持不变。

// demo
struct Student
{
	char name[10];
	int age;
	char phone[12];
} s;

fread(&s, sizeof(s),1, pf);
printf("%s %d %s\n", s.name, s.age, s.phone);

😏 三组 scanfprintf 函数对比

先来了解一下 sprintfsscanf

在这里插入图片描述

在这里插入图片描述

与格式化输出、输入函数百分之九十都是相似的,使用方法就不言而喻了。

然后总体来看一下这三组函数:

在这里插入图片描述

三组函数的参数都是基本相似的,只是使用的对象不同。

在这里插入图片描述

😍 文件版通讯录

有了上面的文件操作知识,我们就可以将之前写动态内存版本的通讯录再进一步的改善,只需要改动两个点:

  1. 打开通讯录时,需要加载磁盘上的通讯录信息
  2. 关闭通讯录时,需要将通讯录信息保存在磁盘上

这里使用的二进制的读写,因为是在想不出文本读写怎么操作(尴尬)。

🙂 将通讯录信息保存在文件中

// 将通讯录内容刷新到磁盘上
void SaveContact(const Contact* con)
{
	assert(con);

	// 文件打开
	FILE* pf = fopen("contact.dat", "wb");
	if (pf == NULL)
	{
		perror("SaveContact::fopen");
		return;
	}

	// 输出
	for (int i = 0; i < con->size; i++)
	{
		fwrite(con->data + i, sizeof(PeoInform), 1, pf);
	}

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

🙂 加载文件中的通讯录信息

// 加载磁盘上的通讯录内容
void LoadContact(Contact* con)
{
	assert(con);

	// 打开文件
	FILE* pf = fopen("contact.dat", "rb");
	if (pf == NULL)
	{
		perror("LoadContact::fopen");
		return;
	}

	// 输入
	int i = 0;
	while (fread(con->data + i, sizeof(PeoInform), 1, pf))
	{
		CheckCapacity(con);
		i++, con->size++;
	}

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

源码: 文件版通讯录

🌈 总结

文件操作在日后的编程中将会显得愈发重要,这些知识文件的冰山一角,所以一定要好好掌握这些知识点。

下一章: 文件的随机读写

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

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

相关文章

registry私有仓库搭建

目录 一、搭建本地仓库 1、首先下载registry镜像 2、在daemon.json文件中添加私有镜像仓库地址 3、运行registry容器 4、为镜像打标签 5、上传到私有仓库 6、列出私有仓库的所有镜像 7、列出私有仓库的centos 镜像有哪些tag 8、先删除原有的centos的镜像&#xff0c;再…

(九)Geoprocessing地理处理框架——ArcToolbox内容简介

&#xff08;九&#xff09;Geoprocessing地理处理框架——ArcToolbox内容简介 目录 &#xff08;九&#xff09;Geoprocessing地理处理框架——ArcToolbox内容简介 1.工具集简介1.1 3D Analyst工具箱&#xff1a;1.2分析工具箱:1.3制图工具箱:1.4转换工具箱:1.5Data Interoper…

有必要给孩子买台灯吗?分享四款高品质的护眼台灯

有必要使用护眼台灯&#xff0c;尤其是有近视现象的孩子们。 现在很多孩子小学就开始近视了&#xff0c;保护视力刻不容缓呀! 很多人不知道&#xff0c;其实劣质光线是最大的眼睛杀手 给孩子随便买便宜的台灯&#xff0c;看着一样能用&#xff0c;其实时间久了 对孩子眼睛的…

java版企业电子招投标系统源代码之了解电子招标投标全流程

随着各级政府部门的大力推进&#xff0c;以及国内互联网的建设&#xff0c;电子招投标已经逐渐成为国内主流的招标投标方式&#xff0c;但是依然有很多人对电子招投标的流程不够了解&#xff0c;在具体操作上存在困难。虽然各个交易平台的招标投标在线操作会略有不同&#xff0…

每天一道算法练习题--Day20 第一章 --算法专题 --- ----------滑动窗口(思路 + 模板)

笔者最早接触滑动窗口是滑动窗口协议&#xff0c;滑动窗口协议&#xff08;Sliding Window Protocol&#xff09;&#xff0c;属于 TCP 协议的一种应用&#xff0c;用于网络数据传输时的流量控制&#xff0c;以避免拥塞的发生。 发送方和接收方分别有一个窗口大小 w1 和 w2。窗…

机器学习小结之KNN算法

文章目录 前言一、概念1.1 机器学习基本概念1.2 k 值1.3 距离度量1.4 加权方式 二、实现2.1 手写实现2.2 调库 Scikit-learn2.3 测试自己的数据 三、总结3.1 分析3.2 KNN 优缺点 参考 前言 ​ KNN (K-Nearest Neighbor)算法是一种最简单&#xff0c;也是一个很实用的机器学习的…

VLAD Diffusion,一个更好用且易于安装的Stable Diffusion Web UI

VLAD Diffusion 是我们前面介绍过的 AUTOMATIC1111/stable-diffusion-webui的一个定制的更新&#xff0c;它主要是为了更频繁发布的更新和错误修复。它包含 新的安装程序&#xff0c;并且提供了高级CUDA调优不在依赖Accelerate&#xff0c;因为Accelerate是分布式的&#xff0…

setTimeout不准时,CSS精准实现计时器功能

实际开发过程中&#xff0c;我们会经常遇到&#xff0c;首次进入页面进行相应提示&#xff0c;然后指定时间后自动消失或者前端时钟展示等需求。 按照传统方案&#xff0c;我们可以使用 setTimeout 实现。但其存在&#xff1a;实际延时比设定值更久的情况。 setTimeout 不准时…

单个案例奖金2000元!AidLux AI 应用案例悬赏征集活动第二期选题上线啦

AidLux AI 应用案例悬赏征集活动第一期开发者作品新鲜"出炉"啦&#xff01; 得益于AidLux在AI应用部署端的极大优势&#xff0c;开发者们在短时间内轻松落地了大批AI应用。 其中&#xff0c;不乏后厨老鼠识别告警系统、粮食作物特定病虫害告警系统、基于视觉的仰卧起…

专注主业、管控风险,中国春来的“非激进式扩张”

近日&#xff0c;中国春来发布截至2023年2月28日止六个月的中期业绩公告&#xff0c;期内收入同比增长14.2%至7.49亿元&#xff0c;利润同比上涨32%至3.31亿元&#xff0c;交出了亮眼的成绩单。 探究中国春来业绩上涨的原因&#xff0c;关键在于扩大招生。而招生规模很大程度上…

ChatGPT终于被我问到胡说八道的程度了!

问&#xff1a;Python是强类型语言&#xff0c;还是弱类型语言 chatgpt&#xff1a;Python是强类型语言。Python很少会隐式地转换变量的类型&#xff0c;所以Python是强类型的语言 问&#xff1a;什么是强类型语言 chatgpt&#xff1a;强类型语言是指在编程语言中&#xff0…

自动控制原理笔记-频率响应法-系统的开环频率特性图的绘制

目录 一、系统的开环对数频率特性图&#xff08;Bode图&#xff09; 绘制方法I&#xff1a;&#xff08;各环节的Bode图求和&#xff09; 绘制方法II&#xff1a;&#xff08;不求和&#xff0c;直接绘图&#xff09; 二、系统的开环幅相特性图&#xff08;Nyquist图、极坐标…

Linux网络编程——网络基础[1]

目录 1.网络发展 2.初识协议 2.1协议分层 2.2OSI七层模型 2.3TCP/IP四层(五层)模型 3.网络传输的基本流程 3.1协议报头 3.2局域网通信原理 3.3广域网通信原理 3.4数据包的封装和分用 4.网络中的地址管理 1.网络发展 计算机是帮助人解决计算问题的&#xff0c;而人…

实在智能出席第六届数字中国建设峰会,入围2022年信息技术应用创新优秀解决方案榜单

最美榕城四月天&#xff0c;山海之间尽显数字澎湃。这一周来&#xff0c;实在智能来到了“有福之州”&#xff0c;为数字中国建设增添实在色彩。 4月25日&#xff0c;实在华夏行抵达福州站&#xff0c;与众多生态合作伙伴携手共话数字发展新未来&#xff1b; 4月26日&#xff…

在DARTS空间中进行神经架构搜索(NAS)

前言 神经架构搜索(NAS)&#xff1a;自动化设计高性能深度神经网络架构的技术神经架构搜索任务主要有三个关键组成部分&#xff0c;即&#xff1a; 模型搜索空间&#xff0c;定义了一个要探索的模型的集合一个合适的策略作为探索这个模型空间的方法一个模型评估器&#xff0c;…

全景丨0基础学习VR全景制作,平台篇第15章:热点功能-音图文

大家好&#xff0c;欢迎观看蛙色VR官方——后台使用系列课程&#xff01; 功能说明 应用场景 热点&#xff0c;指在全景作品中添加各种类型图标的按钮&#xff0c;引导用户通过按钮产生更多的交互&#xff0c;增加用户的多元化体验。 音图文热点&#xff0c;即音频、图片、文字…

如何将redis部署在linux操作系统中:(十分详细的步骤)

一&#xff1a;通过虚拟机安装一个linux环境 注意&#xff1a;安装一个带有可视化界面的环境 将指标选中install centos7 按enter键 选择自己需要的语言 选中gui&#xff1a;桌面&#xff08;可视化界面) 只需要配置软件设置即可&#xff0c;其他的则进行默认配置进行 root用…

【stm32疑难杂症】:Error: L6218E: Undefined symbol TIM_Cmd (referred from timer.o).

项目场景&#xff1a; 在使用工程是发现问题&#xff1a; ..\OBJ\OLED.axf: Error: L6218E: Undefined symbol TIM_Cmd (referred from timer.o). ..\OBJ\OLED.axf: Error: L6218E: Undefined symbol TIM_ITConfig (referred from timer.o). ..\OBJ\OLED.axf: Error: L6218E: …

少儿编程scratch

目录 少儿编程scratch 第一课 孙悟空72变 说绕口令的小猫 欢乐音乐会 海底世界 多变的章鱼哥 益虫与害虫 猫抓老鼠 监控报警器 神奇的画笔 小蝙蝠逃生记 森林里的体育课 寻找小狗哈哈 我是小小饲养员 青蛙王子 少儿编程scratch 第一课 需求描述&#xff1a;scratch的…

安卓缓存那些事情面试,一篇全部搞定

安卓缓存那些事情面试&#xff0c;一篇全部搞定 安卓缓存机制LruCache算法手写Bitmap的三级缓存一.为什么Bitmap三级缓存&#xff1f;二.原理三.代码 Bitmap的二次采样和质量压缩一.为什么二次采样二.哪二次采样三.代码:网络请求图片进行尺寸压缩四.质量压缩1.方法介绍2.案例&a…