文件操作(二):学习笔记10

news2024/11/22 14:35:26

目录

一.概念梳理

         1.文件的分类

         2.程序运行时,内存和外存数据交流的过程

二.文件缓冲区

三.常用的文件读写函数笔记

1.常用格式化文件读写函数

(1)格式化文件写入函数

用fprintf进行文件写入操作:

(2)格式化文件读取函数

用fscanf进行文件读取

2.常用的二进制文件读写函数

(1)二进制文件写入函数

fwrite函数写入文件示例: 

(2)二进制文件读取函数 

四.文件的随机读写

五. 文件读取结束后的相关判定

文件读取的结束标志:

应用实例:

六 .附


一.概念梳理

1.文件的分类

程序文件运行时会向操作系统申请使用内存空间(内存的读写效率十分高)

除操作系统的内存空间以外,其余的数据存储介质可以称为外存(比如硬盘,网络等)

数据文件还可以进一步分为两类:

根据数据的组织形式,数据文件可分为文本文件或者二进制文件。


文本文件:在外存上以ASCII码的形式存储,在存储前需要将内存中的二进制数据进行转换以ASCII字符的形式存储的文件就是文本文件(文本文件中存储的都是字符类型数据)

二进制文件:数据在内存中以二进制的形式存储,如果不加转换的输出到外存,就是二进制文件(二进制文件中存储的都是二进制数据)。

举个例子:

如有整数10000,如果以ASCII码的形式输出到磁盘,则磁盘中占用5个字节(每个字符一个字节),而二进制形式输出,则在磁盘上只占4个字节(VS2013测试)
 

代码实测:

  

2.程序运行时,内存和外存数据交流的过程

计算机各存储区块发生的数据传递都要经过复杂的中间过程,这些中间过程被抽象为流的概念并且被开发人员统一封装起来以方便编码人员使用。流由文件信息区进行管理,用户通过FILE*的文件指针来维护文件信息区。

一个C程序在运行时,会默认打开三个流:

stdin:    标准输入流  (可通过FILE*类型指针来维护)   (与scanf相关的流)

stdout:  标准输出流  (可通过FILE*类型指针来维护)   (与printf相关的流)

stderr:  标准错误流   (可通过FILE*类型指针来维护)

 二.文件缓冲区

数据从C程序内存流出或从外存流入C程序内存过程中间会被暂时先存入一个文件缓冲区。

 

系统会自动地在内存中为程序中每一个正在使用的文件开辟一块“文件缓冲区”

1.从程序内存向磁盘输出数据会先送到内存中的缓冲区,装满缓冲区后才一起送到磁盘上

2.从磁盘向计算机读入数据,则从磁盘文件中读取数据输入到内存缓冲区(充满缓冲区),然后再从缓冲区逐个地将数据送到程序数据区(程序变量等).

如果程序运行过程中,我们不想让数据停留在数据缓冲区,可以用fflush函数刷新缓冲区,就可以立马完成数据的传递。

缓冲区的大小根据C编译系统决定的。

编码验证程序缓冲区的存在:

fflush函数:int fflush( FILE *stream );

int main()
{
	FILE* pf = fopen("test.txt", "w");
	fputs("abcdef", pf); //先将字符串放在输出缓冲区
	printf("睡眠10秒-已经写数据了,打开test.txt文件,发现文件没有内容\n");
	Sleep(10000);
	printf("刷新缓冲区\n");
	fflush(pf);          //刷新缓冲区时,才将输出缓冲区的数据写到文件(磁盘)
	printf("再睡眠10秒-此时,再次打开test.txt文件,文件有内容了\n");
	Sleep(10000);
	fclose(pf);
	//注:fclose在关闭文件的时候,也会刷新缓冲区
	pf = NULL;
	return 0;
}

因为有缓冲区的存在,C语言在操作文件的时候,需要及时刷新缓冲区或者在文件操作结束的时候关闭文件。
否则,可能导致读写文件的问题(类似于游戏的坏档)

三.常用的文件读写函数笔记

1.常用格式化文件读写函数

(1)格式化文件写入函数

fprintf函数首部: int fprintf( FILE *stream, const char *format , ......);

函数的功能是将格式化的数据写入到FILE*stream维护的文件中,使用的方法类似于printf函数(printf函数是将格式化的数据写入到屏幕终端上打印出来),由于fprintf适用于所有输出流,所以将stdout(输出流)作为fprint的FILE*类型的实参则fprint可以用于替代print(print只能用于将数据输出到屏幕终端上).

函数返回写入的数据的字节数

 

fprintf替代printf示例:

从上图例子中可以看到两者的作用完全相同。

fprintf的形参表中的...表示的是可变参数,是一种非常特殊的形参(形参的类型和个数都是可变的)。

用fprintf进行文件写入操作:

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

int main()
{
	struct S s = { "zhangsan", 20, 95.5 };
	FILE* pf = fopen("test.txt", "w");
	if (NULL == pf)
	{
		perror("fopen");
		return 1;
	}
	//格式化的写入文件
	fprintf(pf, "%s %d %f\n", s.name, s.age, s.score);
	fprintf(pf, "%s %d %f\n", s.name, s.age, s.score);
	fprintf(pf, "%s %d %f\n", s.name, s.age, s.score);
	fprintf(pf, "%s %d %f\n", s.name, s.age, s.score);
	//关闭文件
	fclose(pf);
	pf = NULL;
	return 0;
}

(2)格式化文件读取函数

fsacnf函数首部:int fscanf( FILE *stream, const char *format ,... );

函数的功能是将FILE*stream维护的文件中的内容以格式化的方式读取到指定的程序内存空间中,使用的方式类似于scanf(scanf只能用于从终端中读取数据),同样地,如果将stdin作为fscanf的FILE*实参,fsanf也可以替代scanf。

函数返回所读取到的格式化数据个数

fscanf替代scanf示例:

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;
}

用fscanf进行文件读取

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

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.score));
	
	//打印看数据
	printf("%s %d %f\n", s.name, s.age, s.score);
	
	//关闭文件
	fclose(pf);
	pf = NULL;
	return 0;
}

2.常用的二进制文件读写函数

由于数据在内存中是以二进制的形式存储的,因此二进制文件读写操作的过程中无须对数据进行转化(我个人认为以二进制的形式读写文件效率应该会更高)

(1)二进制文件写入函数

fwrite函数首部:

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

函数的功能是将count个size字节大小的对象以二进制序列的形式从buffer指向的空间写入到FILE*所维护的文件中。写入到文件中的数据将保留内存中原有的二进制序列的形式。

函数返回写入的格式化数据个数,返回值若小于count则说明发生了写入异常

fwrite函数写入文件示例: 

struct S
{
	char name[20];
	int age;
	float score;
};
int main()
{
	struct S s = { "张三", 20, 98.5};
	FILE* pf = fopen("test.txt", "wb");
	if (NULL == pf)
	{
		perror("fopen");
		return 1;
	}
	//写文件
	fwrite(&s, sizeof(struct S), 1, pf);
	//关闭文件
	fclose(pf);
	pf = NULL;
	return 0;
}

(2)二进制文件读取函数 

fread函数首部:size_t fread( void *buffer, size_t size, size_t count, FILE *stream );

函数的功能将FILE*stream维护的文件中count个size字节大小的二进制数据读取到buffer所指向的程序变量空间中

函数返回值是读取的size字节大小的数据个数

fread函数读取示例:

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

//测试二进制的写函数:fread
int main()
{
	struct S s = { 0};
	FILE* pf = fopen("test.txt", "rb");
	if (NULL == pf)
	{
		perror("fopen");
		return 1;
	}
	//读文件
	int ret = fread(&s, sizeof(struct S), 1, pf);
	printf("%s %d %f\n", s.name, s.age, s.score);

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

四.文件的随机读写

文件读写时,会有一个文件读写指针指向文件中被读写的空间(指针会随着读写的过程进行偏移),一些函数可以根据文件读写指针的位置和偏移量来定位文件读写指针以及移动文件读写指针

(1)fseek函数

int fseek ( FILE * stream, long int offset, int origin );
参数origin有三种选择:(三个标准库中的常量)

三个常量分别代表文件读写指针的参考起始位置。

函数的功能是将文件读写指针移动到相对于起始位置的offset偏移量(以字节为单位)处。

#include <stdio.h>
int main()
{
	FILE* pFile;
	pFile = fopen("example.txt", "wb");
	fputs("This is an apple.", pFile);
	fflush(pFile);
	fseek(pFile, 9, SEEK_SET);
	fputs(" sam", pFile);
	fclose(pFile);
	return 0;
}

(2)ftell函数

long int ftell ( FILE * stream );
函数的功能是返回文件读写指针相对于起始位置的偏移量

#include <stdio.h>
int main()
{
	FILE* pFile;
	long size;
	pFile = fopen("test.txt", "rb");
	if (pFile == NULL) perror("Error opening file");
	else
	{
		fseek(pFile, 0, SEEK_END); // non-portable
		size = ftell(pFile);
		fclose(pFile);
		printf("Size of myfile.txt: %ld bytes.\n", size);
	}
	return 0;
}


 文件中的二进制数据总大小恰好为28个字节

(3)rewind函数
 void rewind ( FILE * stream );

函数功能是让文件读写指针回到起始位置

int main()
{
	int n;
	FILE* pFile;
	char buffer[27];
	pFile = fopen("myfile.txt", "w+");
	for (n = 'A'; n <= 'Z'; n++)
	{
		fputc(n, pFile);
	}
	rewind(pFile);
	fread(buffer, 1, 26, pFile);
	fclose(pFile);
	buffer[26] = '\0';
	puts(buffer);
	return 0;
}

五. 文件读取结束后的相关判定

文件读取的结束标志:

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

fgetc 判断返回值是否为 EOF (若为EOF则说明读取结束)
fgets 判断返回值是否为 NULL(若为NULL则说明读取结束)

2.二进制文件的读取结束判断,判断返回值是否小于实际要读的个数
fread判断返回值是否小于传入的实参count

文件读取结束后,需要对读取结束的原因进行判定这时就需要用到feof函数和ferror函数

feof函数:int feof( FILE *stream );

ferror函数:int ferror( FILE *stream );

文件读取结束后调用上述两个函数

调用feof若返回值为真,则说明是文件正常读取遇到了结束标志而结束的。

调用ferror若返回值为假,则说明文件是在读取过程中出错了而结束的。

应用实例:

#include <stdio.h>
#include <stdlib.h>
int main(void)
{
	// 注意:int,非char,要求处理EOF
    int c; 
	FILE* fp = fopen("test.txt", "r");
	if (!fp) 
    {
		perror("File opening failed");
		return EXIT_FAILURE;
	}
	//fgetc 当读取失败的时候或者遇到文件结束的时候,都会返回EOF
	while ((c = fgetc(fp)) != EOF)
	{
		putchar(c);
	}
	//判断是什么原因结束的
	if (ferror(fp))
		puts("I/O error when reading");
	else if (feof(fp))
		puts("End of file reached successfully");
	fclose(fp);
}

六 .附

sscanf函数首部:int sscanf( const char *buffer, const char *format ,... );

函数的功能是将buffer指向的字符串中的数据进行以format规定的格式转换,读取到可变参数实参指针指向的空间中

sprintf函数首部:int sprintf( char *buffer, const char *format ,  ... );

函数的功能是将可变参数实参指针指向的空间中的数据以format规定的格式转换为字符串并写入buffer指向的空间中

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

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

相关文章

Java枚举类与注解

目录 一、枚举类的使用 枚举类的实现 枚举类的属性 自定义枚举类 步骤 举例 使用enum定义枚举类 使用说明 举例 Enum类的主要方法 实现接口的枚举类 二、注解的使用 概述 常见的Annotation示例 自定义Annotation&#xff08;参照SupressWarnings 定义&#xff09…

一不小心,登上支付宝开发者社区热文榜单Top3

大家好&#xff0c;我是小悟 那天中午要午休的时候&#xff0c;看到微信通讯录新朋友有个红色1&#xff0c;像俺这种有强迫症的&#xff0c;那不得去把它点掉。打开一看&#xff0c;加好友的备注是“我是熊二&#xff0c;支付宝开发者社区运营”。 收到支付宝社区的运营添加微…

【ROS】dynamic_reconfigure配置详细说明

文章目录 文章目录 前言 一、编写.cfg文件 二、为节点配置dynamic_reconfigure 总结 前言 dynamic_reconfigure配置是ROS中为了方便用户对程序中的参数进行实时调整而推出的工具&#xff0c;配置好自己的dynamic_reconfigure文件后&#xff0c;可以很方便的使用ROS提供的r…

2022-12-18 网工进阶(三十八)MPLS LDP---LDP基础、工作原理(会话、标签的发布和管理、特性)、配置举例

LDP概述 LDP是MPLS的一种控制协议&#xff0c;相当于传统网络中的信令协议&#xff0c;负责FEC的分类、标签的分配以及LSP的建立和维护等操作。LDP规定了标签分发过程中的各种消息以及相关处理过程。 LDP的工作过程主要分为两部分&#xff1a;LSR之间建立LDP会话&#xff1b;…

一种小型项目的超时机制方案

设计背景 在小型项目中&#xff0c;状态机的跳转往往依赖于某个事件的状态&#xff0c;因此监控某个事件是否处于超时状态就至关重要&#xff1b; 注意事项 超时机制应该能够准确的判断出事件是否真正超时&#xff0c;并预留出设置自定义超时处理的接口&#xff1b;超时机制…

什么是大数?大数有什么用?如何使用大数?

0 什么是大数 如果基本的整数和浮点数精度不能够满足需求&#xff0c;那么可以使用 javamath 包中两个很有用的类:BigInteger和 BiDecimal。 这两个类可以处理包含任意长度数字序列的数值。 BigInteger类实现任意精度的整数运算&#xff0c;BigDecimal实现任意精度的浮点数运算…

Android | Fragment

Android Fragment Fragment 概念 Fragment 表示应用界面中可重复的一部分&#xff0c;Fragment 定义和管理自己的布局&#xff0c;具有自己的生命周期&#xff0c;并且可以处理自己的输入事件。fragment 不能独立存在&#xff0c;而是必须由 Activity 或另一个 fragment 托管…

麦克纳姆轮(麦轮)原理

一、麦轮原理 麦克纳姆轮&#xff1a;简称麦轮&#xff0c;由轮毂和围绕轮毂的辊子组成。 辊子&#xff1a;没有动力的从动小滚轮。 麦克纳姆轮辊子轴线和轮毂轴线夹角是45度。 A轮&#xff08;左旋&#xff09;与B轮&#xff08;右旋&#xff09;互为镜像关系 麦轮在车上的…

Go语言开发小技巧易错点100例(五)

往期回顾&#xff1a; Go语言开发小技巧&易错点100例&#xff08;一&#xff09;Go语言开发小技巧&易错点100例&#xff08;二&#xff09;Go语言开发小技巧&易错点100例&#xff08;三&#xff09;Go语言开发小技巧&易错点100例&#xff08;四&#xff09; …

打工人必学的法律知识(五)——《女职工劳动保护特别规定》

女职工劳动保护特别规定https://flk.npc.gov.cn/detail2.html?ZmY4MDgwODE2ZjNjYmIzYzAxNmY0MTBmMWVkNTE0NTE &#xff08;2012年4月18日国务院第200次常务会议通过 2012年4月28日中华人民共和国国务院令第619号公布 自公布之日起施行&#xff09;第一条 为了减少和解决女职工…

如何减少频繁创建数据库连接的性能损耗?

为极速开发出一套某垂直领域电商系统&#xff0c;采用最简架构&#xff1a; 前端一台Web服务器运行业务代码后端一台DB服务器存储业务数据 大多系统初生时就是这样&#xff0c;只是随业务不但发展变得复杂&#xff0c;架构迭代。系统上线后&#xff0c;虽用户量不大&#xf…

第十三届蓝桥杯大赛软件类决赛Java大学B组C题——左移右移

【问题描述】 小蓝有一个长度为 N 的数组&#xff0c;初始时从左到右依次是 1, 2, 3, . . . N。 之后小蓝对这个数组进行了 M 次操作&#xff0c;每次操作可能是以下 2 种之一&#xff1a; 左移 x&#xff0c;即把 x 移动到最左边。右移 x&#xff0c;即把 x 移动到最右边。 …

数字信号处理音频FIR去噪滤波器(基于MATLAB GUI的开发完整代码+报告+课设)

1、内容简介利用MATLAB GUI设计平台&#xff0c;用窗函数法设计FIR数字滤波器&#xff0c;对所给出的含有噪声的声音信号进行数字滤波处理&#xff0c;得到降噪的声音信号&#xff0c;进行时域频域分析&#xff0c;同时分析不同窗函数的效果。将文件解压至一个目录下&#xff0…

ithewei的2022年度总结

窗外的雨&#xff0c;顺着晒衣架汇聚成豆大的珠&#xff0c;落到一楼庭院顶棚上&#xff0c;嘀嗒不停&#xff1b; 路上的车&#xff0c;由远及近&#xff0c;又由近及远&#xff0c;疾驰而过&#xff1b; 床边的猫&#xff0c;也已入睡&#xff0c;时不时发出一两声细微的鼾声…

面试问:@Resource 和@Autowired 的区别是什么?该怎么回答

Resource 和 Autowired 这两个注解的作用都是Spring生态里面去实现 Bean 的依赖注入 Autowired注解的作用 Autowired是Spring里面提供的一个注解&#xff0c;它默认是根据类型来实现Bean的依赖注入。 Autowired注解里面有一个required属性&#xff0c;它的默认值是true&#…

人大金仓数据库安装篇

图形化安装 规划安装路径与修改目录属主 先用root账户挂载金仓镜像包 mount -o loop /install/KingbaseES_V008R006C005B0023_Lin64_single_install.iso /mnt 切换kingbase用户来安装金仓数据库 进入挂载目录/mnt执行./setup.sh 将金仓注册为系统服务 /KingbaseES/V8/Scrip…

1592_AURIX_TC275_PMU_部分安全措施

全部学习汇总&#xff1a; GreyZhang/g_TC275: happy hacking for TC275! (github.com) UCB的几种状态通过寄存器的数值可以直接获取到。启动代码会识别到UCB的错误&#xff0c;如果识别到后悔停止继续&#xff0c;因此不会启动MCU。启动代码也会检查HSM是否存在以及是否需要启…

基于TensorFlow2搭建神经网络实现鸢尾花iris.txt分类

分三步&#xff1a;本地读取鸢尾花数据集搭建神经网络优化本地读取鸢尾花数据集读取本地数据集的两种方法读取本地数据集有两种方法&#xff1a;&#xff08;1&#xff09;利用pandas中的函数读取&#xff0c;并处理成神经网络需要的数据结构pd.read_csv(文件名, header第几行作…

使用码云Gitee创建代码仓库并提交代码

目录 1. 登录Gitee官网 2. 创建代码仓库 3. 克隆仓库到本地 4. 提交代码到Gitee仓库 官方文档&#xff1a;创建你的第一个仓库 - Gitee.com 1. 登录Gitee官网 官网地址&#xff1a;Gitee - 基于 Git 的代码托管和研发协作平台 2. 创建代码仓库 点击图中加号创建仓库&am…

String的不可变性

1.什么是不可变对象 如果一个对象在创建之后就不能再改变它的状态&#xff0c;那么这个对象是不可变的&#xff08;Immutable&#xff09;。不能改变状态的意思是&#xff0c;不能改变对象内的成员变量&#xff0c;包括基本数据类型变量的值不能改变&#xff0c;引用类型的变量…