C语言教程——文件处理(2)

news2025/1/28 1:15:49

目录

前言

一、顺序读写函数(续)

1.1fprintf

1.2fscanf

1.3fwrite

1.4fread

二、流和标准流

2.1流

2.2标准流

2.3示例

三、sscanf和sprintf

3.1sprintf

3.2sscanf

四、文件的随机读写

4.1fseek

4.2ftell

4.3rewind

五、文件读取结束的判定

5.1feof相关判断知识

六、文件缓冲区

总结



前言

昨天最顺序读写函数了解了四个,今天接着学习。


一、顺序读写函数(续)

1.1fprintf

格式化输出函数

int fprintf ( FILE * stream, const char * format, ... );

第一个参数就是文件,第二个参数就是与printf的后面的参数一样。

我们可以用代码来掩饰一下:

我们先定义一个结构体变量:

struct S {
	char name[20];
	int age;
	int Id;
};

之后调用fprintf函数写入文件

struct S s = { "zhangsan",14,12345 };
fprintf(df,"%s %d %d\n",s.name,s.age,s.Id);

同样还是作用于之前的目标文件。

我们打开文件就可以看见,成功的运行了。

1.2fscanf

这里就是格式化读写文件

int fscanf ( FILE * stream, const char * format, ... );

通过fscanf就可以进行访问,一样的我们把创建一个结构体来接收:

FILE* df = fopen("D:\\project\\text.txt", "r");
struct S s = {0};
fscanf(df, "%s %d %d", s.name, &(s.age), &(s.Id));
printf("%s %d %d\n", s.name, s.age, s.Id);

之后就可以通过fscanf访问之前存入的数据,我们可以打印出来,然后运行一下看看:

我们可以看见,刚才访问的数据就实现了。

1.3fwrite

接着是二进制出入文件函数

size_t fwrite ( const void * ptr, size_t size, size_t count, FILE * stream );

第一个参数就是要传入的原始数据指针(因为不知道是什么类型,所以之类用void*类型表示),第二个是这个原始数据的大小,第三个是要传入文件的个数,最后一个就是要传入的文件。

我们可以用代码来演示:

#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>

struct S {
	char name[20];
	int age;
	float score;
};

int main()
{
	struct S s = { "李白",34,99.9 };
	//打开文件
	FILE* df = fopen("D:\\project\\text.txt", "wb");
	if (df == NULL)
	{
		perror("fopen::");
		return 1;
	}
	//二进制写入
	fwrite(&s, sizeof(struct S), 1, df);
	//关闭文件
	fclose(df);
	df = NULL;
	return 0;
}

注意这里的方式改用了wb,因为它是为了输出数据,打开⼀个⼆进制⽂件,这里把结构体中的数据变为了二进制进行写入文件,我们可以打开文件看看:

这里发现变成了一堆不认识的东西,如果我们用二进制打开就可以看到:

这是一堆二进制,如果对二进制进行分析,就会得到一些数据。

1.4fread

二进制读取函数

size_t fread ( void * ptr, size_t size, size_t count, FILE * stream );

我们发现这里的参数和二进制写入是一模一样的,所以话不多说,我们可以直接写入代码。

这里打开文件的方式改为‘rb’。

在代码之前我们可以看一下txt文件里是什么:

我们还不认识,接下来用fread来读取后输出,看看打印出来的是什么。

#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>

struct S {
	char name[20];
	int age;
	float score;
};

int main()
{
	struct S s = {0};
	//打开文件
	FILE* df = fopen("D:\\project\\text.txt", "rb");
	if (df == NULL)
	{
		perror("fopen::");
		return 1;
	}
	//二进制读取
	fread(&s, sizeof(struct S), 1, df);
	printf("%s %d %f\n", s.name, s.age, s.score);
	//关闭文件
	fclose(df);
	df = NULL;
	return 0;
}

我们运行后:

发现是我们之前的数据,这里第三个数不一样的原因是因为我们使用的是浮点数进行输出,所以这里精度会出现偏差。

二、流和标准流

我们前面可以看到有流的概念,所以在这里再说一下流的概念。

2.1流

我们程序的数据需要输入到各种外部设备,也需要从外部设备中获得数据,不同的外部设备的输入输出操作各不相同,为了方便程序员对各种设备进行方便的操作,我们抽象出了流的概念,我们可以把流想成一条河,用的时候从里面拿,不用的时候可以还回去。

C程序针对文件、画面、键盘等的数据输入输出操作都是通过流操作的。一般情况下,我们想要向流里写数据,或者从流中读取数据,都是打开流,然后操作。

2.2标准流

C程序在启动的时候,默认启动了三个流,分别是:

stdin 标准输入流,在大多数的环境中从键盘输入,scanf函数就是从标准输入流中读取数据。

stdout 标准输出流,大多数的环境中输出至显示器界面,printf函数就是将信息输出到标准输出流中。

stderr 标准错误流,大多数环境中输出到显示器界面。

这是默认打开的三个流,我们使用scanf,printf等函数就可以直接进行输入输出函数的。

stdin、stdout、stderr三个流的类型是:FILE*,通常称为文件指针。

我们可以通过文件函数来访问流从而输入输出:

2.3示例

这里通过直接调用stdin从输入流读数据,完了显示到输出流中。

struct S {
	char name[20];
	int age;
	float score;
};

int main()
{
	struct S s = { 0 };
	fscanf(stdin, "%s %d %f", s.name,&(s.age), &(s.score));
	fprintf(stdout, "%s %d %f\n", s.name, s.age, s.score);
	return 0;
}

运行一下我们可以看到:

这里实现了读取和输出。

我们也可以用fputc和fgetc来掩饰,十分的简单易懂:

int main()
{
	
	int c=fgetc(stdin);
	fputc(c, stdout);
	return 0;

}

运行结果就是:

输入一个字符,输出一个字符

三、sscanf和sprintf

3.1sprintf

int sprintf ( char * str, const char * format, ... );

这个函数可以把后面的类型成员放到前面的字符串中。

返回值:成功后,将返回写入的字符总数。此计数不包括自动追加在字符串末尾的其他 null 字符。
失败时,将返回负数。

我们可以通过代码来理解:

struct S {
	char name[20];
	int age;
	float score;
};

首先我们先定义了一个结构体,然后通过后续操作把结构体中的成员按照原本的类型格式放到字符串中:

int main()
{
	struct S s = { "张三",39,99.99 };
	char arr[100] = { 0 };
	sprintf(arr, "%s %d %f", s.name, s.age, s.score);
	printf("%s\n", arr);
	return 0;
}

我们运行之后就可以看见:

确实按照原本的格式放到了arr字符串中。

3.2sscanf

int sscanf ( const char * s, const char * format, ...);

str是要读取的字符串,format是格式化字符串,...是根据格式化字符串提供的格式来指定要解析的数据类型和要存放数据的变量。

sscanf函数根据格式化字符串的格式,从字符串中提取数据,并将数据存入对应的变量中。它可以用来解析字符串中的数字、字符、字符串等数据,并将其存入变量中。

所以我们可以通过代码来实现一下,把上面字符串中的数据提取出来,然后放到一个新的结构体中:

int main()
{
	struct S s = { "张三",39,99.99 };
	char arr[100] = { 0 };
	sprintf(arr, "%s %d %f", s.name, s.age, s.score);
	printf("%s\n", arr);

	struct S s1 = {0};
	sscanf(arr, "%s %d %f", s1.name, &(s1.age), &(s1.score));
	printf("%s %d %f", s1.name, s1.age, s1.score);

	return 0;
}

这就实现了从字符串中提取,然后放到新的结构体中,我们打印新的结构体中的数据,就可以看见:

实现了新结构体的打印。

四、文件的随机读写

4.1fseek

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

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

这里第一个参数就是那个要访问的流,第二个是偏移量,第三个是选哪种方式,这里有三种方式。

ConstantReference position
SEEK_SETBeginning of file(文件开头)
SEEK_CURCurrent position of the file pointer(当前位置)
SEEK_ENDEnd of file *(文件结尾)

我们这里还用之前的文件,里面给上:

代码文件打开时,是指在a前面的。就可以通过代码来演示:

int main()
{
	FILE* df = fopen("D:\\project\\text.txt", "r");
	int ch = 0;
	ch=fgetc(df);
	printf("%c\n", ch);
	ch = fgetc(df);
	printf("%c\n", ch);
	ch = fgetc(df);
	printf("%c\n", ch);
}

这里通过fgetc来获取当前字符,函数使用一次那么指针就往后走一个。这时候运行就是:

我们如果想返回去访问之前的字符,那么就可以用fseek来实现,因为此时是在d前面,我们如果要访问下一个字符为b,如果定义的是当前位置,那么指针就需要往前2个位置,偏移量也就是-2:

printf("%c\n", ch);
fseek(df, -2, SEEK_CUR);
ch = fgetc(df);
printf("%c\n", ch);

我们通过运行就可以看到:

这就访问到了b。除了这一种方法还可以用另外两种,相对于开始b的偏移量就是1,相对于末尾b的偏移量就是-3,这样对参数进行赋值,那么就可以成功实现访问b。

但是如果我们不知道偏移量为多少,那么就可以用下面这个函数。

4.2ftell

返回当前指针位置

long int ftell ( FILE * stream );

传入文件指针,那么返回的就是一个整形,这个整形就是文件指针当前指向的位置。 

这里针对之前的代码:

printf("%d\n", ftell(df));

结果显示的就是2. 

4.3rewind

将指针返回到开始,起始位置。

void rewind ( FILE * stream );

这里也是针对之前的代码: 

rewind(df);
printf("%d\n", ftell(df));

 结果就是0.

还有很多的函数,感兴趣的可以自己看看。

五、文件读取结束的判定

5.1feof相关判断知识

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

1.文本文件读取是否结束:

fgetc判断结束是否为EOF,返回失败返回EOF

fgets判断结束是否为NULL,返回失败是返回一个空指针

2.二进制文件的读取结束判断:

fread判断返回值是否小于实际要读的个数

文件读取结束了,结束后想知道结束的原因:

feof返回为真的话,就说明是文件正常读取到了结束标志而结束的。

ferror返回为真的话,就说明文件在读取过程中出错了而结束的。

六、文件缓冲区

文件缓冲区是在计算机系统中用来临时存放文件数据的一块内存区域。当计算机需要读取或写入文件数据时,通常会先将数据读取到文件缓冲区中,然后再根据需要将数据从缓冲区移动到内存或磁盘中。

文件缓冲区的存在可以提高文件读写的效率。由于磁盘操作相对较慢,每次读写都需要进行磁盘寻址,而将数据读取到缓冲区中可以避免频繁的磁盘操作。当数据写入缓冲区时,系统可以选择将数据缓存一段时间后再进行实际的写入操作,从而避免频繁的磁盘写入。

文件缓冲区一般由操作系统提供,可以是内核级别的缓冲区或用户级别的缓冲区。内核级别的缓冲区由操作系统管理,对于用户程序来说是透明的;而用户级别的缓冲区由程序员自己管理,可以根据需要进行灵活的控制。

使用文件缓冲区需要注意及时刷新缓冲区和关闭文件。当数据写入缓冲区后,如果不及时刷新缓冲区,数据可能不会立即写入磁盘中;而关闭文件时,系统会自动将缓冲区中的数据写入磁盘。

总之,文件缓冲区是一种提高文件读写效率的技术,可以有效减少磁盘操作次数,提高系统性能。

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

因为有缓冲区的存在,C语⾔在操作⽂件的时候,需要做刷新缓冲区或者在⽂件操作结束的时候关闭⽂件


总结

提示:这里对文章进行总结:
例如:以上就是今天要讲的内容,本文仅仅简单介绍了pandas的使用,而pandas提供了大量能使我们快速便捷地处理数据的函数和方法。

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

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

相关文章

ios打包:uuid与udid

ios的uuid与udid混乱的网上信息 新人开发ios&#xff0c;发现uuid和udid在网上有很多帖子里是混淆的&#xff0c;比如百度下&#xff0c;就会说&#xff1a; 在iOS中使用UUID&#xff08;通用唯一识别码&#xff09;作为永久签名&#xff0c;通常是指生成一个唯一标识&#xf…

.NET9增强OpenAPI规范,不再内置swagger

ASP.NETCore in .NET 9.0 OpenAPI官方文档ASP.NET Core API 应用中的 OpenAPI 支持概述 | Microsoft Learnhttps://learn.microsoft.com/zh-cn/aspnet/core/fundamentals/openapi/overview?viewaspnetcore-9.0https://learn.microsoft.com/zh-cn/aspnet/core/fundamentals/ope…

hot100_234. 回文链表

给你一个单链表的头节点 head &#xff0c;请你判断该链表是否为回文链表。如果是&#xff0c;返回 true &#xff1b;否则&#xff0c;返回 false 。 示例 1&#xff1a; 输入&#xff1a;head [1,2,2,1] 输出&#xff1a;true 示例 2&#xff1a; 输入&#xff1a;head …

【超详细】ELK实现日志采集(日志文件、springboot服务项目)进行实时日志采集上报

本文章介绍&#xff0c;Logstash进行自动采集服务器日志文件&#xff0c;并手把手教你如何在springboot项目中配置logstash进行日志自动上报与日志自定义格式输出给logstash。kibana如何进行配置索引模式&#xff0c;可以在kibana中看到采集到的日志 日志流程 logfile-> l…

IPoIB(IP over InfiniBand)数据接收与发送机制详解

IPoIB&#xff08;IP over InfiniBand&#xff09;是一种在InfiniBand网络上实现IP协议的技术&#xff0c;它允许在InfiniBand网络上传输IP数据包。IPoIB通过将IP数据包封装在InfiniBand的数据包中&#xff0c;实现了在InfiniBand网络上的高效通信。本文将详细分析IPoIB如何接收…

Spring Boot - 数据库集成04 - 集成Redis

Spring boot集成Redis 文章目录 Spring boot集成Redis一&#xff1a;redis基本集成1&#xff1a;RedisTemplate Jedis1.1&#xff1a;RedisTemplate1.2&#xff1a;实现案例1.2.1&#xff1a;依赖引入和属性配置1.2.2&#xff1a;redisConfig配置1.2.3&#xff1a;基础使用 2&…

JAVAweb学习日记(八) 请数据库模型MySQL

一、MySQL数据模型 二、SQL语言 三、DDL 详细见SQL学习日记内容 四、DQL-条件查询 五、DQL-分组查询 聚合函数&#xff1a; 分组查询&#xff1a; 六、DQL-分组查询 七、分页查询 八、多表设计-一对多&一对一&多对多 一对多-外键&#xff1a; 一对一&#xff1a; 多…

Scratch游戏作品 | 僵尸来袭——生存大战,保卫你的领地!

今天为大家推荐一款刺激十足的Scratch射击生存游戏——《僵尸来袭》&#xff01;在这个充满危机的世界里&#xff0c;僵尸不断向你袭来&#xff0c;利用你的战斗技能与策略道具生存下来&#xff0c;成为最后的幸存者&#xff01;✨ 源码现已在小虎鲸Scratch资源站免费下载&…

C# 自定义随机字符串生成

目录 简介 调用方式&#xff1a; 详细说明 1.外层方法封装 2.定义字符组合 3.按长度生成 简介 随机字符串&#xff0c;包含数字&#xff0c;字母&#xff0c;特殊符号等&#xff0c;随机拼凑&#xff0c;长度可输入 为了生成效率&#xff0c;长度大于1024的&#xff0c…

【C++探索之路】STL---string

走进C的世界&#xff0c;也意味着我们对编程世界的认知达到另一个维度&#xff0c;如果你学习过C语言&#xff0c;那你绝对会有不一般的收获&#xff0c;感受到C所带来的码云风暴~ ---------------------------------------begin--------------------------------------- 什么是…

rust 发包到crates.io/ 操作流程 (十)

第一步github登录 https://crates.io/ 在项目里面login&#xff1a; cargo login ciol4sMwaR61YvzWniodRlssk6RfS4HcZTU --registry crates-io如果不想每次带 这个&#xff0c;就执行 vim ~/.cargo/config.toml 添加下面 [registry] default "crates-io"git a…

MongoDB部署模式

目录 单节点模式&#xff08;Standalone&#xff09; 副本集模式&#xff08;Replica Set&#xff09; 分片集群模式&#xff08;Sharded Cluster&#xff09; MongoDB有多种部署模式&#xff0c;可以根据业务需求选择适合的架构和部署方式。 单节点模式&#xff08;Standa…

国自然重点项目|代谢影像组学只能预测肺癌靶向耐药的关键技术与应用|基金申请·25-01-25

小罗碎碎念 今天和大家分享一个国自然重点项目&#xff0c;项目执行年限为2019.01 - 2023.12&#xff0c;直接费用为294万。 项目聚焦肺癌靶向治疗中药物疗效预测难题&#xff0c;整合多组学与代谢影像数据展开研究。 在研究过程中&#xff0c;团队建立动物模型获取多维数据&am…

NFT Insider #166:Nifty Island 推出 AI Agent Playground;Ronin 推出1000万美元资助计划

引言&#xff1a;NFT Insider 由 NFT 收藏组织 WHALE Members、BeepCrypto 联合出品&#xff0c; 浓缩每周 NFT 新闻&#xff0c;为大家带来关于 NFT 最全面、最新鲜、最有价值的讯息。每期周报将从 NFT 市场数据&#xff0c;艺术新闻类&#xff0c;游戏新闻类&#xff0c;虚拟…

Word 中实现方框内点击自动打 √ ☑

注&#xff1a; 本文为 “Word 中方框内点击打 √ ☑ / 打 ☒” 相关文章合辑。 对第一篇增加了打叉部分&#xff0c;第二篇为第一篇中方法 5 “控件” 实现的详解。 在 Word 方框内打 √ 的 6 种技巧 2020-03-09 12:38 使用 Word 制作一些调查表、检查表等&#xff0c;通常…

Cpp::静态 动态的类型转换全解析(36)

文章目录 前言一、C语言中的类型转换二、为什么C会有四种类型转换&#xff1f;内置类型 -> 自定义类型自定义类型 -> 内置类型自定义类型 -> 自定义类型隐式类型转换的坑 三、C强制类型转换static_castreinterpret_castconst_castdynamic_cast 四、RTTI总结 前言 Hell…

4.flask-SQLAlchemy,表Model定义、增删查改操作

介绍 SQLAlchemy是对数据库的一个抽象 开发者不用直接与SQL语句打交道 Python对象来操作数据库 SQLAlchemy是一个关系型数据库 安装 flask中SQLAlchemy的配置 from flask import Flask from demo.user_oper import userdef create_app():app Flask(__name__)# 使用sessi…

20250122-正则表达式

1. 正则标记 表示一位字符&#xff1a;\\ 表示指定的一位字符&#xff1a;x 表示任意的一位字符&#xff1a;. 表示任意一位数字&#xff1a;\d 表示任意一位非数字&#xff1a;\D 表示任意一个字母&#xff1a;[a-zA-Z]&#xff08;大写或小写&#xff09; 表示任意一个…

SpringBoot3+Vue3开发学生选课管理系统

功能介绍 分三个角色登录&#xff1a;学生登录&#xff0c;老师登录&#xff0c;教务管理员登录&#xff0c;不同用户功能不同&#xff01; 1.学生用户功能 选课记录&#xff0c;查看选课记录&#xff0c;退选。选课管理&#xff0c;进行选课。通知管理&#xff0c;查看通知消…

媒体新闻发稿要求有哪些?什么类型的稿件更好通过?

为了保证推送信息的内容质量&#xff0c;大型新闻媒体的审稿要求一向较为严格。尤其在商业推广的过程中&#xff0c;不少企业的宣传稿很难发布在这些大型新闻媒体平台上。 媒体新闻发稿要求有哪些&#xff1f;就让我们来了解下哪几类稿件更容易过审。 一、媒体新闻发稿要求有哪…