【C语言进阶】文件操作:文件的打开与文件的读写以及文本文件和二进制文件

目录

1、为什么使用文件

2、什么是文件 

2.1 程序文件

2.2 数据文件 

2.3 文件名

3、文件的打开和关闭 

3.1文件指针 

3.2文件的打开与关闭 

4、文件的顺序读写 

4.1 几个函数的区别

5、文件随机读写 

 5.1 fseek

5.2 ftell 

5.3 rewind 

6、文本文件和二进制文件 

7、文件读取结束的判定 

 7.1 被错误使用的feof

8、文件缓冲区



1、为什么使用文件

我们学习结构体时,写了静态通信录,可以在通讯录中增加、删除数据,此时数据是存放在内存中,当程序退出的时候,数据又要重新录入,当程序退出时,通讯录中的数据就不存在了,等下次运行通讯录,数据又要重新录入。我们想既然是通讯录就应该把信息记录下来,只有我们删除数据时,数据才不复存在。

使用文件主要是为了数据持久化、用户交互和数据交换。文件可以存储数据,即使程序关闭或计算机重启,数据也不会丢失。同时,文件也是程序与用户之间以及不同程序之间交换信息的重要媒介。

2、什么是文件 

磁盘上的文件就是文件,但在程序设计中,我们一般只谈程序文件和数据文件

2.1 程序文件

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

2.2 数据文件 

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

这篇文章所要讨论的是数据文件。以前所处理的数据的输入输出都是以终端为对象的,即从终端的键盘输入数据,运行结果显示到显示器上。其实有时候我们会把信息输出到磁盘上,当需要的时候再从磁盘上把数据读取到内存中使用,这里处理的就是磁盘文件。

2.3 文件名

一个文件要有一个唯一的文件标识,以便用户识别和引用。文件名包含3部分:文件路径+文件名主干+文件后缀

比如:c:\code\test.txt

3、文件的打开和关闭 

3.1文件指针 

 缓冲文件系统中,关键的概念是“文件类型指针”,简称"文件指针“。

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

//文件类型声明
typedef struct _iobuf
{
	char *_ptr;
	int _cnt;
	char *_base;
	int _flag;
	int _file;
	int _charbuf;
	int _bufsiz;
	char *_temfname;
}FILE;

不同的C编译器的FILE类型包含的内容不完全相同,但基本差不多。

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

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

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

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

3.2文件的打开与关闭 

文件在读写之前应该先打开文件,在使用结束之后应该关闭文件。

在编写程序的时候,在打开文件的同时,都会返回一个FILE*  的指针变量指向该文件,也相当于建立了指针和文件的关系。

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

//打开文件
FILE* fopen(const char* filename, const char* mode);//filename是文件名,mode是文件打开模式(读或写)
//关闭文件
int fclose(FILE* stream);

文件的使用: 

#include<stdio.h>
#include<errno.h>
#include<string.h>
int main()
{
	FILE* pf=fopen("test.txt", "r");//在对应路径创建文件名为“text”,系统默认扩展名为txt
	if (pf == NULL)
	{
		printf("%s\n", strerror(errno));
		return 1;
	}
	//读文件
	//......
	//关闭文件
	fclose(pf);
	pf = NULL;
	return 0;
}
文件使用方式含义如果指定文件不存在
"r"(只读)为了输入数据打开一个已经存在的文本文件出错
"w"(只写)为了输出数据打开一个文本文件建立一个新文件
"a"(追加)向文本文件尾添加数据建立一个新文件
"rb"(只读)为了输入数据打开一个二进制文本出错
"wb"(只写)为了输出数据打开一个二进制文本建立一个新文件
"ab"(追加)向一个二进制文件尾添加数据出错
"r+"(读写)为了读和写打开一个文本文件出错
"w+"(读写)为了读和写建立一个文本文件建立一个新文件
"a+"(读写)打开一个文件,在文件尾进行读写建立一个新文件
"rb+"(读写)为了读和写打开一个二进制文件出错
"wb+"(读写)为了读和写新建一个二进制文件建立一个新文件
"ab+"(读写)为了追加和读新建一个二级制文本建立一个新文件

4、文件的顺序读写 

功能函数名适用场景
字符输入函数fgetc所有输入流
字符输出函数fputc所有输出流
文本行输入函数fgets所有输入流
文本行输出函数fputs所有输出流
格式化输入函数fscanf所有输入流
格式化输出函数fprintf所有输出流
二进制输入fread文件
二进制输出fwrite文件
/举个栗子
#include<stdio.h>
#include<errno.h>
#include<string.h>
int main()
{
	FILE* pf = fopen("text.txt.txt", "w");
	if (pf == NULL)
	{
		printf("%s\n", strerror(errno));
		return 1;
	}
	//写文件
	char i = 0;
	for (i = 'a'; i <= 'z'; i++)
	{
		fputc(i, pf);
	}
	//关闭文件
	fclose(pf);
	pf == NULL;
	return 0;
}

其他函数就不在这里一一举例了,大家可以在cplusplus.com官网查看函数的使用方法 

 注意:如果文件里面有原始数据,我们在写文件时会把原始数据给覆盖掉,如果不想销毁就改成追加。

4.1 几个函数的区别

 scanf:是针对标准输入的的格式化输入语句

 printf:是针对标准输出的的格式化输出语句

 fscanf:是针对所有输入流的格式化输入语句

 fprintf: 是针对所有输出流的格式化输出语句

 sscanf:从一个字符串中转换出格式化的数据

 sprintf:是把一个格式化的数据转换成字符串

//sprintf
//int sprintf(char* str, const char* format, ...);
//将格式化数据写入字符串
struct S
{
	char name[20];
	int age;
	float score;
};
int main()
{
	struct S s = { "张三",20,50.5f };
	char buffer[100] = { 0 };
	sprintf(buffer, "%s %d %f\n", s.name, s.age, s.score);
	printf("%s\n", buffer);//字符串打印(此时已经转化为字符串)
	//sscanf
    //int sscanf(const char* s, const char* format, ...);
   //从字符串中读取格式化数据
	sscanf(buffer, "%s %d %f", s.name, &(s.age), &(s.score));
	printf("%s %d %lf\n", s.name, s.age, s.score);
	return 0;
}

5、文件随机读写 

 5.1 fseek

 根据文件指针的位置和偏移量来定位文件指针

int fseek ( FILE * stream, long int offset, int origin );

//文件中放的是abcdef
int main()
{
	FILE* pf = fopen("text.txt.txt", "r");
	if (pf == NULL)
	{
		printf("%s\n", strerror(errno));
		return 1;
	}
	//定位文件指针
	fseek(pf, 2, SEEK_SET);
	int ch = fgetc(pf);
	printf("%c\n", ch);
	//关闭文件
	fclose(pf);
	pf == NULL;
	return 0;
}

5.2 ftell 

 返回文件指针相对应起始位置的偏移量

long int ftell (FILE* sream);

int main()
{
	FILE* pf = fopen("text.txt.txt", "r");
	if (pf == NULL)
	{
		printf("%s\n", strerror(errno));
		return 1;
	}
	//定位文件指针
	fseek(pf, 2, SEEK_SET);
	int ch = fgetc(pf);
	printf("%c\n", ch);
	printf("%d\n", ftell(pf));
	//关闭文件
	fclose(pf);
	pf == NULL;
	return 0;
}

5.3 rewind 

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

void rewind(FILE* stream);

int main()
{
	FILE* pf = fopen("text.txt.txt", "r");
	if (pf == NULL)
	{
		printf("%s\n", strerror(errno));
		return 1;
	}
	//定位文件指针
	fseek(pf, 2, SEEK_SET);
	int ch = fgetc(pf);
	printf("%c\n", ch);
	printf("%d\n", ftell(pf));
	rewind(pf);
	ch = fgetc(pf);
	printf("%c\n", ch);
	fclose(pf);
	pf == NULL;
	return 0;
}

6、文本文件和二进制文件 

根据数据的组织形式,数据文件被称为文本文件二进制文件。根据在内存中以二进制的形式存储,如果不加转换的输出到外存,就是二进制文件;如果要求在外存上以ASCII码值的形式存储,则需要在存储前转换。以ASCII字符的形式存储的文件就是文本文件

一个数据在内存中是如何存储的?

字符一律以ASCII码值的形式存储,数值型数据既可以用ASCII形式存储,也可以用二进制形式存储;如果有整数10000,以ASCII码的形式输出到磁盘,则磁盘中占用5个字节(每个字符一个字节),而二进制形式输出,则在磁盘上只占4个字节

int main()
{
	int a = 100000;
	FILE* pf=fopen("text.txt.txt", "wb");
	if (pf == NULL)
	{
		perror("fopen");
		return 1;
	}
	fwrite(&a, 4, 1, pf);
	fclose(pf);
	pf = NULL;
	return 0;
}

7、文件读取结束的判定 

 7.1 被错误使用的feof

 注意:在文件读取过程中,不能用feof函数的返回值直接用来判断文件是否结束。而是应用于当文件文件读取结束的时候,判断是读取失败结束,还是遇到文件尾结束。

1、文本文件读取是否结束,判断返回值是否为EOF(fgetc)或NULL(fgets)

2、二进制文件读取结束判断,判断返回值是否小于实际要读的个数 

8、文件缓冲区 

ANSIC标准采用“缓冲文件系统”处理的数据文件的,所谓缓冲文件系统是指系统自动地在内存中为程序中每一个正在使用的文件开辟一块“文件缓冲区”。从内存此磁盘输出数据会先送到内存中的缓冲区,装满缓冲区才一起送到磁盘上。如果从从磁盘向计算机读入数据,则从磁盘文件中读取数据输入到内存缓冲区(充满缓冲区),然后再从缓冲区逐个将数据送到程序数据区(程序变量等)。缓冲区的大小根据C编译系统决定的。 

#include<stdio.h>
#include<Windows.h>
int main()
{
	FILE* pf = fopen("test.txt.txt", "w");
	fputs("abcdef", pf);
	printf("睡眠10秒-已经写数据,打开test.txt.txt文件,发现文件没有内容\n");
	Sleep(10000);
	printf("刷新缓冲区\n");
	fflush(pf);//刷新缓冲区时,才将缓冲区的数据写到文件
	printf("再睡眠10秒-此时再次打开test.txt.txt文件,文件有内容了\n");
	Sleep(10000);
	fclose(pf);//关闭文件时也会刷新缓冲区
	pf = NULL;
	return 0;
}

 结论:因为缓冲区的存在,C语言在操作文件时,需要做刷新缓冲区或者在文件操作结束的时候关闭文件。否则可能导致读写文件的问题!

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

APM32F003评测,基本参数,点LED

简介 该是一个基于APM32F003 32位Cortex-M0 工业级 单片机开发板。主频高达48MHz&#xff0c;AHB 总线、APB 总线&#xff0c;无需外部晶振即可运行&#xff0c;价格实惠。为专业人士、工业ODM、AIoT爱好者、DIY爱好者和创作者提供了一个可靠、低成本和高性能的平台。 这款开发…

LangChain学习圣经:从0到1精通LLM大模型应用开发的基础框架

尼恩&#xff1a;LLM大模型学习圣经PDF的起源 在40岁老架构师 尼恩的读者交流群(50)中&#xff0c;经常性的指导小伙伴们改造简历。 经过尼恩的改造之后&#xff0c;很多小伙伴拿到了一线互联网企业如得物、阿里、滴滴、极兔、有赞、希音、百度、网易、美团的面试机会&#x…

MFC3d立体按钮制作

1、本程序基于前期我的博客文章MFC用CButtonST类实现图片透明按钮(免费源码下载) 2、添加CeXDib.cpp CeXDib.h ShadeButtonST.cpp ShadeButtonST.h到项目文件夹下&#xff0c;和FileView中如图。 3、在ButtonShadeDlg.h中添加代码 #include "ShadeButtonST.h" #in…

回文串算法题

回文串是一个正着读和反着读顺序一样的字符串。"aba" 是回文串&#xff0c;"abba" 是回文串&#xff0c;"abc" 不是回文串。 回文串的题目&#xff0c;都要使用一个基本的逻辑&#xff0c;就是判断当前这个字符串是不是回文串。以 c 为例&#…

无限光年人工智能技术创新PMO负责人端煜受邀为第十三届中国PMO大会演讲嘉宾

全国PMO专业人士年度盛会 无限光年&#xff08;上海&#xff09;技术有限公司人工智能技术创新PMO负责人、原字节跳动朝夕光年PMO总监端煜先生受邀为PMO评论主办的2024第十三届中国PMO大会演讲嘉宾&#xff0c;演讲议题为“中国传统哲学在LLM企业项目管理应用中的思考与实践”。…

移植2D物理引擎到LVGL

背景 在LVGL交流群&#xff0c;有网友提出想要移植物理引擎到LVGL&#xff0c;遂有了本文。阅读本文需要对IDF和LVGL有所了解 过程 2D物理引擎有很多&#xff0c;经过一番调研选择了Chipmunk2D 下载源码 此处省略一万字&#xff0c;Github访问可能会有些慢 添加文件 将…

达梦8 内存泄漏泄漏原因分析之一

在实际使用过程中经常发现DMSERVER进程在OS中的内存占用使用远远超过实际情况。原因有很多&#xff0c;下面列出其中一种&#xff1a; 测试库版本 SQL> select id_code;LINEID ID_CODE ---------- ----------------------------------- 1 --03134283938-2022…

DPDK基础组件一(mbuf、ring、pktmbuf_pool)

一、rte_mbuf 此部分转自:https://zhuanlan.zhihu.com/p/616314276 1.mbuf结构 mbuf是报文中的描素的结构体,是整个转发过程中最核心的数据结构之一。主要针对于mbuf的常用API与基本原理做一个简单的介绍。 mbuf:报文内存存储结构,存储在mempool中mempool:使用环形缓冲…

如何选择D类音频放大器(数字功率放大器)

1 简介 多年来&#xff0c;音频内容一直在不断发展。从当地唱片店购买 12 英寸 LP 黑胶唱片的时代已经成为过去&#xff0c;现在我们通过流式传输几乎可即时播放云端的任何内容。虽然一些音频爱好者会为了获得新奇体验而重拾黑胶唱片&#xff0c;但今天绝大多数的音频都是以数…

基于Nginx和Consul构建自动发现的Docker服务架构——非常之详细

基于Nginx和Consul构建自动发现的Docker服务架构 文章目录 基于Nginx和Consul构建自动发现的Docker服务架构资源列表基础环境一、安装Docker1.1、Consul节点安装1.2、registrator节点安装 二、案例前知识点2.1、什么是Consul 三、基于Nginx和Consul构建自动发现的Docker服务架构…

[NOIP2015 提高组] 子串

题目背景 NOIP2015 Day2T2 题目描述 有两个仅包含小写英文字母的字符串 A A A 和 B B B。 现在要从字符串 A A A 中取出 k k k 个互不重叠的非空子串&#xff0c;然后把这 k k k 个子串按照其在字符串 A A A 中出现的顺序依次连接起来得到一个新的字符串。请问有多少…

从集合论到位运算

前言 本文将扫清位运算的迷雾&#xff0c;在集合论与位运算之间建立一座桥梁。 在高中&#xff0c;我们学了集合论&#xff08;set theory&#xff09;的相关知识。例如&#xff0c;包含若干整数的集合 S{0,2,3}。在编程中&#xff0c;通常用哈希表&#xff08;hash table&…

计算机网络学习2

文章目录 信道复用技术 第三章数据链路层概述数据链路层的三个重要问题封装成帧和透明传输差错检测可靠传输的相关基本概念可靠传输的实现机制停止等待协议回退N帧协议选择重传协议 点对点协议PPP共享式以太网网络适配器和MAC地址CSMA_CD协议的基本原理共享式以太网的争用期共享…

【计算机毕业设计】331基于微信小程序的家庭财务管理系统

&#x1f64a;作者简介&#xff1a;拥有多年开发工作经验&#xff0c;分享技术代码帮助学生学习&#xff0c;独立完成自己的项目或者毕业设计。 代码可以私聊博主获取。&#x1f339;赠送计算机毕业设计600个选题excel文件&#xff0c;帮助大学选题。赠送开题报告模板&#xff…

开源VS闭源:大模型发展路径之争,你站哪一派?

文章目录 引言一、数据隐私1.1开源大模型的数据隐私1.2 闭源大模型的数据隐私1.3 综合考量 二、商业应用2.1 开源大模型的商业应用2.2 闭源大模型的商业应用2.3 商业应用的综合考量 三、社区参与3.1 开源大模型的社区参与3.2 闭源大模型的社区参与3.3 综合考量 结论 引言 在人…

数据库与数据库管理系统 MySQL的安装 SQL语言学习:DDL、DML

day51 数据库 数据库&#xff08;database&#xff09;就是一个存储数据的仓库。为了方便数据的存储和管理&#xff0c;它将数据按照特定的规律存储在磁盘上。 通过数据库管理系统&#xff0c;可以有效地组织和管理存储在数据库中的数据&#xff0c;如数据库管理系统MySQL 数据…

html three.js 引入.stl模型示例

1.新建一个模块用于放置模型 <div id"chart_map" style"width:800px;height:500px"></div> 2. 引入代码根据需求更改 <!-- 在head或body标签内加入以下链接 --> <script src"https://cdn.jsdelivr.net/npm/three0.137/build/t…

c++的string一键介绍

前言&#xff1a; 这篇文章旨在帮助读者回忆如何使用string&#xff0c;并提醒注意事项。它不是一篇详细的功能介绍&#xff0c;而是一篇润色文章。 先展示重载函数&#xff0c;如果该函数一笔不可带过&#xff0c;就先展示英文原档&#xff08;附带翻译&#xff09;&#xf…

基于语音信号MFCC特征提取和GRNN神经网络的人员身份检测算法matlab仿真

目录 1.算法运行效果图预览 2.算法运行软件版本 3.部分核心程序 4.算法理论概述 4.1 MFCC特征提取 4.2 GRNN神经网络概述 5.算法完整程序工程 1.算法运行效果图预览 2.算法运行软件版本 MATLAB2022a 3.部分核心程序 ...............................................…

Django序列化器中is_valid和validate

今天上班的时候分配了一个任务&#xff0c;是修复前端的一个提示优化&#xff0c;如下图所示&#xff1a; 按照以往的经验我以为可以直接在validate上进行校验&#xff0c;如何抛出一个异常即可 &#xff0c;例如&#xff1a; class CcmSerializer(serializers.ModelSerialize…