高阶C语言之五:(数据)文件

目录

文件名

 文件类型

文件指针

 文件的打开和关闭

文件打开模式 

文件操作函数(顺序)

0、“流”

1、字符输出函数fputc

2、字符输入函数fgetc 

3、字符串输出函数fputs

4、 字符串输入函数fgets

 5、格式化输入函数fscanf

6、格式化输出函数fprintf

7、二进制输入函数fread

8、二进制输出函数fwrite

 几种输入输出

文件随机读写函数

1、fseek:定位指针

2、ftell:返回指针位置

3、rewind:重定位指针

4、实例

 文本文件和二进制文件

 文件读取结束的判定

1、被错误使用的feof函数

2、判断文件是否读取结束:

3、实例

文件缓冲区


改造通讯录(可保存信息):month_11/test_12 · Hera_Yc/bit_C_学习 - 码云 - 开源中国

本文相关代码:month_11/test_16/main.c · Hera_Yc/bit_C_学习 - 码云 - 开源中国

文件:即硬盘上的文件,文件将数据直接存放在电脑的硬盘上,做到了数据的持久化

在程序设计当中,程序员所说的文件一般分为两种:程序文件、数据文件。

  • 程序文件:包括源程序文件(后缀为 .c )、目标文件(windows环境后缀为 .obj )、可执行程序文件(windows环境后缀为 .exe )。
  • 数据文件:文件的内容不一定是程序,而是程序运行时读写的数据。

个人对文件操作的理解:

  1. 文件操作这里的本质就是一堆库函数,懂得这些库函数就可以对函数进行操作了。
  2. 文件的使用与动态内存类似,需要“开辟”和“释放”,即文件的打开和关闭。
  3. 相对于内存来说,文件(硬盘)是一种外部设备。

文件名

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

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

如:"C:\Users\Desktop\newc++file.cpp"

文件标识通常称为文件名

windows和Linux允许没有后缀名的文件。

 文件类型

包含在头文件<stdio.h>中

Q:什么是文件类型?

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

 文件类型声明:

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

        文件类型并不是真正文件的类型,而是将硬盘文件的一些信息作为一组数据存放在内存中,CPU通过这组数据来对文件进行操作。 

        在对文件进行操作时,可以将文件看作一个FILE类型的变量,FILE类型的变量是在使用文件时,系统自动创建的。

文件指针

FILE* pf;

文件指针:定义pf是一个指向FILE类型的数据变量。通过文件指针变量能够找到与它关联的文件


 文件的打开和关闭

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

文件的使用:打开文件--->读出\写入数据--->关闭文件。

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

函数声明:

FILE* fopen(const char* filename, const char* mode);
//filename :文件名
//mode     :打开模式

int fclose(FILE* stream);
//stream   :文件指针
文件打开模式 
  • 'r'模式:这是“只读”模式。如果文件不存在,尝试打开将失败。文件指针位于文件开头,不会清空文件原有内容。

  • 'w'模式:这是“只写”模式。如果文件存在,它将被清空并从头开始写入;如果文件不存在,将创建一个新文件。文件指针位于文件开头。

  • 'a'模式:这是“追加”模式。如果文件存在,写入的数据将添加到文件末尾,不会清空原有内容;如果文件不存在,将创建一个新文件。文件指针位于文件结尾。

  • 'r+'模式:这是“读写”模式。文件必须存在,文件指针位于文件开头。可以在文件任意位置读取或写入内容,写入操作会覆盖原有位置的内容。

  • 'w+'模式:这也是“读写”模式。它类似于'w'模式,但是它允许读取操作。打开文件后,会清空文件内原有的内容。

  • 'a+'模式:这同样是“读写”模式。它类似于'a'模式,但是它允许读取操作。写入内容时,只会追加在文件尾部。

  • 还有很多操作模式,感兴趣读者自行查阅。

实例:

int main()
{
	//打开文件
	FILE* pf = fopen("test.txt", "r");//fopen的参数是:路径 、操作
	if (pf == NULL)
	{
		perror("fopen");
        //perror等价于printf("open:%s\n",strerror(errno));
		return 1;
	}
	//文件操作
	//...

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

文件操作函数(顺序)

头文件<stdio.h>

0、“流”

文件操作函数中的输入输出是相对于内存而言的:

        屏幕和键盘也算一种外部设备(通过流),为什么C程序不用主动的去打开或关闭这些外部设备?

1、任何一个C程序会默认打开3个流

  • FILE* stdin  - 标准输入流 (键盘)
  • FILE* stdout  - 标准输出流 (屏幕)
  • FILE* stderr  - 标准错误流 (屏幕)
int main()
{
	struct S s = { 0 };

	FILE* pf = fopen("test.txt", "r");
	if (pf == NULL)
	{
		perror("fopen");
		return 1;
	}
	//把文件看作命令行
	//在命令行里面输入程序数据。输入到内存
	//因此是“输入”函数
	fscanf(pf, "%s %d %f", s.arr, &(s.age), &(s.score));
	//printf("%s %d %f", s.arr, s.age, s.score);
	//等价于
	fprintf(stdout, "%s %d %f", s.arr, s.age, s.score);

	fclose(pf);
	pf = NULL;
	return 0;
}

1、字符输出函数fputc

函数声明:

int fputc( int c, FILE *stream );

使用:

int main()
{
	//打开文件
	FILE* pf = fopen("test.txt", "w");// w:写入模式
	if (pf == NULL)
	{
		perror("fopen");
		return 1;
	}
	//写文件
	char i = 0;
	for (i = 'a'; i < 'f'; i++)
	{
		fputc(i, pf);
	}
	fclose(pf);
	pf = NULL;
	return 0;
}
2、字符输入函数fgetc 

函数声明:

int fgetc( FILE *stream );

使用:

int main()
{
	//打开文件
	FILE* pf = fopen("test.txt", "r");// r:读取模式
	if (pf == NULL)
	{
		perror("fopen");
		return 1;
	}

	int ch = '\0';
	while ((ch = fgetc(pf)) != EOF)
	{
		printf("%c\n", ch);
	}
	
	//关闭文件
	fclose(pf);
	pf = NULL;
	return 0;
}
3、字符串输出函数fputs

声明:

int fputs( const char *string, FILE *stream );

使用:

4、 字符串输入函数fgets
char *fgets( char *str, int n, FILE *stream );
//str:数据的存储位置
//n:要读取的最大字符数
//stream:文件指针

使用:

 5、格式化输入函数fscanf
int fscanf( FILE *stream, const char *format [, argument ]... );

使用:

 

int main()
{
	struct S s = { 0 };

	FILE* pf = fopen("test.txt", "r");
	if (pf == NULL)
	{
		perror("fopen");
		return 1;
	}
	//把文件看作命令行
	//在命令行里面输入程序数据
	//因此是“输入”函数
	fscanf(pf, "%s %d %f", s.arr, &(s.age), &(s.score));
	//printf("%s %d %f", s.arr, s.age, s.score);
	//等价于
	fprintf(stdout, "%s %d %f", s.arr, s.age, s.score);

	fclose(pf);
	pf = NULL;
	return 0;
}
6、格式化输出函数fprintf
int fprintf( FILE *stream, const char *format [, argument ]...);

使用:

7、二进制输入函数fread
size_t fread( void *buffer, size_t size, size_t count, FILE *stream );

 使用:

int main()
{
	struct S s = { 0};

	FILE* pf = fopen("test.txt", "rb");//rb:二进制读模式
	if (pf == NULL)
	{
		perror("fopen");
		return 1;
	}

	//以二进制形式写入到文件中
	fread(&s, sizeof(struct S), 1, pf);//读二进制数据,放在s中
	printf("%s %d %f", s.arr, s.age, s.score);
	fclose(pf);
	pf = NULL;
	return 0;
}
8、二进制输出函数fwrite
size_t fwrite( const void *buffer, size_t size, size_t count, FILE *stream );
//buffer:待写入数据的地址
//size:待写入数据的大小
//count:最大写入项数
//stream:指向 FILE 结构的指针

使用:

 几种输入输出

int sprintf( char *buffer, const char *format [, argument] ... );
int sscanf( const char *buffer, const char *format [, argument ] ... );

使用:

int main()
{
	struct S s = { "zhangsan",20,50.5f };
	struct S tmp;
	char buf[100] = { 0 };
	//把s中的格式化数据转化成字符串放到buf中
	sprintf(buf, "%s %d %f", s.arr, s.age, s.score);

	printf("字符串:%s\n", buf);//这里打印的就是一个字符串了

	//从字符串buf中获取一个格式化数据到tmp中
	sscanf(buf, "%s %d %f", tmp.arr, &(tmp.age), &(tmp.score));
	printf("格式化:%s %d %f \n", tmp.arr, tmp.age, tmp.score);
	return 0;
}

补充:动态内存和文件、输入输出、流 

文件随机读写函数

1、fseek:定位指针
int fseek( FILE *stream, long offset, int origin );
//offset:偏移量
//origin:起始位置

fseek通过起始位置+偏移量的方法定位指针 。

origin由三种取值:

  • SEEK_SET:文件起始位置
  • SEEK_CUR:当前指针位置
  • SEEK_END:文件末尾
2、ftell:返回指针位置
long ftell( FILE *stream );
//返回指针相对于起始位置的偏移量
3、rewind:重定位指针
void rewind( FILE *stream );
//使指针返回到起始位置
4、实例
int main()
{
	FILE* pf = fopen("test.txt", "r");
	if (pf == NULL)
	{
		perror("Fopen");
		return 1;
	}

	//当前文件中存放:abcdef
	
	//定位文件指针
	fseek(pf, -2,SEEK_END );
	//当前pf位置 =  -2 + SEEK_END 

	printf("%d\n", ftell(pf));//4
	//相对于文件起始位置的偏移量

	int ch = fgetc(pf);
	printf("%c\n", ch); // 打印的是e

	rewind(pf);//将指针返回到文件起始位置
	printf("%d\n", ftell(pf));//0

	fclose(pf);
	pf = NULL;
}

 文本文件和二进制文件

根据数据的组织形式,数据文件分为:

  • 二进制文件:把内存中的二进制数据,不加任何转化输出到外存中去,就是二进制文件。
  • 文本文件:在外存中以ASCII码的形式存放,在存储前需要转换。


 文件读取结束的判定

1、被错误使用的feof函数

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

int ferror( FILE *stream );
//ferror函数用于检测文件读写过程中是否产生了错误。
int feof( FILE *stream );
//feof函数用于检测是否已到达文件末尾(EOF,End Of File的缩写)
2、判断文件是否读取结束:
  1. 文本文件读取是否结束,判断返回值是否为EOF(fgetc函数),或者为NULL。
  2. 二进制文件读取结束判断,判断返回值是否小于实际要读取的个数。

对于文本文件:

        fgetc:返回值为NULL或者EOF,表示文件读取结束,可以利用feof来对fgetc的返回值进行判断,来确定fgetc为什么读取结束。

对于二进制文件:

        fread:返回值是实际读到的元素的个数,参数count是要求读到的个数。比较返回值和count的关系,就可以判断二进制文件读取是否结束。

3、实例

 ferror和feof两者经常搭配使用:(以二进制读写为例)

enum { SIZE = 5 };

int main()
{
	double a[SIZE] = { 1,2,3,4,5 };
	FILE* fp = ("test.txt", "wb");
	if (fp == NULL)
	{
		perror("Fopen");
		return 1;
	}
	fwrite(a, sizeof(*a), SIZE, fp);
	fclose(fp);

	double b[SIZE];
	fp = fopen("test.txt", "rb");
	if (fp == NULL)
	{
		perror("Fopen");
		return 1;
	}
	size_t ret_code = fread(b, sizeof(*b), 8, fp);
	if (ret_code == SIZE){
		puts("数组读取成功:");
		int i = 0;
		for (i = 0; i < SIZE; i++)printf("%f ", b[i]);
		putchar('\n');
	}
	else{
		if (!feof(fp))
			printf("未达到文件末尾\n");
		else if (ferror(fp)){
			printf("读取错误\n");
		}
	}
	fclose(fp);
	fp = NULL;
	return 0;
}

文件缓冲区

(操作系统会对缓冲区进行详细的讲解,缓冲区也有相应的库操作函数)

        文件缓冲区是内存区预留的一定空间,用以暂时存放读写期间的文件数据。其主要目的是减少读取硬盘的次数,因为硬盘的读写速度相对较慢,而内存的读写速度较快。通过缓冲区,系统可以先将数据读入内存,然后再从内存中读取或写入数据,从而减少了对硬盘的直接访问,提高了数据处理的效率。

 缓冲区存在的意义

  1. 提高数据读写效率:通过缓冲区,系统可以减少对硬盘的直接访问次数,从而提高数据读写的效率。
  2. 保护硬盘:频繁的硬盘访问会加速硬盘的磨损和老化。通过缓冲区,系统可以减少对硬盘的访问次数,从而延长硬盘的使用寿命。
  3. 提高系统稳定性:缓冲区可以平滑数据传输过程中的波动和延迟,提高系统的稳定性和可靠性。

        因为有缓冲区的存在,C语言在操作文件的时候,需要刷新文件缓冲区或在文件操作结束时关闭文件。(fclose,也会自动刷新缓冲区)。

---------------------------------------------------文件到此结束------------------------------------------------------------

         文件了解即可。其实文件没有那么重要,知道最初识得文件操作函数即可,因为在实际项目开发的时候,不可能直接对文件来进行读写,而是利用数据库来存取数据,更加高效。

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

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

相关文章

C#获取视频第一帧_腾讯云媒体处理获取视频第一帧

一、 使用步骤&#xff1a; 第一步、腾讯云开启万象 第二步、安装Tencent.QCloud.Cos.Sdk 包 第三步、修改 腾讯云配置 图片存储目录配置 第四步、执行获取图片并保存 二、封装代码 using System.Text; using System.Threading.Tasks;using COSXML.Model.CI; using COSXML.A…

分词器的概念(通俗易懂版)

什么是分词器&#xff1f;简单点说就是将字符序列转化为数字序列&#xff0c;对应模型的输入。 通常情况下&#xff0c;Tokenizer有三种粒度&#xff1a;word/char/subword word: 按照词进行分词&#xff0c;如: Today is sunday. 则根据空格或标点进行分割[today, is, sunda…

Jenkins更换主题颜色+登录页面LOGO图片

默认主题和logo图片展示 默认主题黑色和白色。 默认LOGO图片 安装插件 Login ThemeMaterial Theme 系统管理–>插件管理–>Available plugins 搜不到Login Theme是因为我提前装好了 没有外网的可以参考这篇离线安装插件 验证插件并修改主题颜色 系统管理–>A…

11.19.2024刷华为OD

文章目录 HJ51HJ53 杨辉三角HJ56HJ57 高精度整数加法HJ58HJ60 简单题HJ63 DNA序列&#xff08;简单题&#xff09;语法知识记录 HJ51 https://www.nowcoder.com/practice/54404a78aec1435a81150f15f899417d?tpId37&tags&title&difficulty0&judgeStatus0&…

C语言零基础入门

一、输入输出 &#xff08;1&#xff09;scanf scanf 是C语言中的一个标准库函数&#xff0c;用于从标准输入&#xff08;通常是键盘&#xff09;读取数据。scanf 函数定义在 <stdio.h> 头文件中。 #include <stdio.h>int main(void) {//读取整数 int num;print…

应聘美容师要注意什么?博弈美业收银系统/管理系统/拓客系统分享建议

随着美容行业的不断发展&#xff0c;成为一名优秀的美容师需要具备一系列重要的技能和品质。无论是在面试过程中还是在实际工作中&#xff0c;以下建议将帮助你在应聘美容师职位时脱颖而出&#xff1a; ▶ 专业技能和资格 首先&#xff0c;确保你具备所需的专业技能和资格。这…

JVM性能分析工具JProfiler的使用

一、基本概念 JProfiler&#xff1a;即“Java Profiler”&#xff0c;即“Java分析器”或“Java性能分析工具”。它是一款用于Java应用程序的性能分析和调试工具&#xff0c;主要帮助开发人员识别和解决性能瓶颈问题。 JVM&#xff1a;即“Java Virtual Machine”&#xff0c…

css鼠标移动效果高亮追随效果

如图所示&#xff0c;鼠标移动有一块高亮随着鼠标移动。代码如下&#xff1a;(vue3篇) <div class"container"><span class"use-hover-hglh-element trail" :style"isShow ? dyStyle : { opacity: 0 }"></span></div>…

PHP屏蔽海外IP的访问页面(源代码实例)

PHP屏蔽海外IP的访问页面&#xff08;源代码实例&#xff09;&#xff0c;页面禁用境外IP地址访问 <?php/*** 屏蔽海外ip访问* 使用ip2long函数得到ip转为整数的值&#xff0c;判断值是否在任一一个区间中* 以下是所有国内ip段* 调用方法&#xff1a;IschinaIp($ALLIPS)* …

现代分布式系统新法宝:基于单元的架构

- 前言 - 数十年来&#xff0c;IT 业界一直在努力掌握分布式系统。然而&#xff0c;随着系统日益复杂&#xff0c;给开发数字产品的组织带来巨大挑战。可以说&#xff0c;分布式系统最棘手的方面之一是面对故障时的可靠性&#xff0c;特别是现代分布式系统使用大量物理与虚拟资…

2.8 群辉 黑群晖 意味断电 抱歉,您所指定的页面不存在。

实验室组装的黑群晖施工时不小心被意味断电&#xff0c;然后出现了如下图&#xff1a; 对于7.1.1的系统来说&#xff0c;这个是由于libsynopkg.so.1和libsynoshare.so.7这两个文件出问题所致。 因此&#xff0c;解决方法也比较简单就是把好的文件恢复到/lib文件夹下即可。 这…

【视频讲解】Python深度神经网络DNNs-K-Means(K-均值)聚类方法在MNIST等数据可视化对比分析...

全文链接&#xff1a;https://tecdat.cn/?p38289 分析师&#xff1a;Cucu Sun 近年来&#xff0c;由于诸如自动编码器等深度神经网络&#xff08;DNN&#xff09;的高表示能力&#xff0c;深度聚类方法发展迅速。其核心思想是表示学习和聚类可以相互促进&#xff1a;好的表示会…

K8S资源限制之ResourceQuota

ResourceQuota介绍 在K8S中&#xff0c;大部分资源都可以指定到一个名称空间下&#xff0c;因此可以对一个名称空间的计算资源&#xff0c;存储资源&#xff0c;资源数量等维度做资源限制。 如限制pod数量、svc数量&#xff0c;控制器数量&#xff0c;限制PVC请求的存储量 注…

【Android原生问题分析】夸克、抖音划动无响应问题【Android14】

1 问题描述 偶现问题&#xff0c;用户打开夸克、抖音后&#xff0c;在界面上划动无响应&#xff0c;但是没有ANR。回到Launcher后再次打开夸克/抖音&#xff0c;发现App的界面发生了变化&#xff0c;但是仍然是划不动的。 2 log初分析 复现问题附近的log为&#xff1a; 用户…

[JavaWeb]微头条项目

完整笔记和项目代码&#xff1a; https://pan.baidu.com/s/1PZBO0mfpwDPic4Ezsk8orA?pwdwwp5 提取码: wwp5 JavaWeb-微头条项目开发 1 项目简介 1.1 业务介绍 微头条新闻发布和浏览平台,主要包含业务如下 用户功能 注册功能登录功能 头条新闻 新闻的分页浏览通过标题关键字搜…

AJAX学习(24.11.1-24.11.14)(包含HTTP协议)

AJAX学习&#xff08;24.11.1-11.14) 来源&#xff1a; 传智 | 高校学习平台-首页 传智播课&#xff1a;黑马程序员 1.服务器和客户端 1.服务器&#xff1a;存放和对外提供资源的电脑。 2.客户端&#xff08;用户&#xff09;&#xff1a;获取和消费资源的电脑。&#xff0…

9.《滑动窗口篇》---①长度最小的子数组(中等)

滑动窗口推导过程 我们不能说一上来就知道这个题目用滑动窗口&#xff0c;然后就使用滑动窗口的方法来做这个题目。 首先我们想到的应该是暴力解法。 接着再优化为滑动窗口 由于数字都是 ≥ 0 的数。因此累加的数越多。和越大。 因此right往后遍历的时候。当发现sum > targe…

《Python网络安全项目实战》项目5 编写网站扫描程序

《Python网络安全项目实战》项目5 编写网站扫描程序 项目目标&#xff1a;任务5.1 暴力破解网站目录和文件位置任务描述任务分析任务实施相关知识任务评价 任务5.2 制作网页JPG爬虫任务分析任务实施相关知识任务评价任务拓展 WEB网站安全渗透测试过程中需要进行目录扫描和网站爬…

React(二)

文章目录 项目地址七、数据流7.1 子组件传递数据给父组件7.1.1 方式一:給父设置回调函数,传递给子7.1.2 方式二:直接将父的setState传递给子7.2 给props传递jsx7.2.1 方式一:直接传递组件给子类7.2.2 方式二:传递函数给子组件7.3 props类型验证7.4 props的多层传递7.5 cla…

Python学习29天

二分查找 # 定义函数冒泡排序法从大到小排列 def bbble_sort(list):# i控制排序次数for i in range(len(list) - 1):# j控制每次排序比较次数for j in range(len(list) - 1 - i):if list[j] < list[j 1]:list[j], list[j 1] list[j 1], list[j] # 定义二分查找函数 def…