文件操作【详解】

news2024/12/23 18:21:30

目录

一、什么是文件

二、文件的打开和关闭

1.文件指针

2.文件的打开和关闭

3.文件的打开方式

三、文件的顺序读写

1.关于输入输出,读和写

2.关于流的介绍

3.操作文件的函数

 字符输入函数 fgetc的使用

 字符输入函数 fputc的使用

 文本行输出函数  fputs()

文本行输入函数 fgets

格式化输出函数 fprintf()

格式化输入函数 fscanf() 

二进制输出 fwrite

二进制输入 fread (从文件到内存)

四、文件的随机读写 

 1.fseek

2.ftell 

3.rewind 

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

六、文件读取结束的判定 

七、文件缓冲区 


前言:当初在通讯录上的数据都是临时存放到内存中的,当程序运行结束的时候,所添加的数据就没有了。等到下一次运行通讯录的时候,数据又需要重新录入,我们发现这样会很繁琐,我们就想着用什么来存着这些数据一直保留着。

于是 这个问题就涉及到数据持久化的问题了,我们一般数据持久化的方法有:数据存放到磁盘文件中、存放到数据库中等方式。所以这里就提到了文件

一、什么是文件

平时我们说的硬盘上的文件就文件

当然在程序设计中,我们一般说到的文件有两种:程序文件、数据文件(从文件功能上来看)。

1.程序文件

  •  源程序文件 (后缀 .c)
  • 目标文件(.obj)
  • 可执行程序(.exe)

2.数据文件

程序运行时读写的数据,需要输入输出的文件

3. 文件名

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

例如 d:\code\test.txt

二、文件的打开和关闭

1.文件指针

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

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

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

创建一个FILE*的指针变量

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

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

2.文件的打开和关闭

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

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

对于打开文件我们一般使用的是 fopen()函数,然后使用fclose()函数来关闭文件

//打开文件
FILE * fopen ( const char * filename, const char * mode );
//关闭文件
int fclose ( FILE * stream );

注意当直接写文件主干时,文件是用相对路径来存放的 

3.文件的打开方式

 

还有关于二进制文件

"rb", "wb", "ab", "rb+", "r+b", "wb+", "w+b", "ab+", "a+b"

三、文件的顺序读写

按顺序进行文件的读写

1.关于输入输出,读和写

首先这是一个相对而言的,例如 相对于一个人而言 读课本是输入(就比如知识存到大脑),然后 写博客就是 输出(把大脑里面的知识输出到博客文章中)。

2.关于流的介绍

这是有些人就有一些疑问,当我们是printf , scanf 又是怎么一回事呢?

通常把显示器称为标准输出文件 printf() 就向这个文件输出数据

通常把键盘称为标准输入文件 scanf() 就向这个文件读取数据

c 语言运行起来 默认打开 三个流 

  • 标准输入流stdin 
  • 标准输入流stdout
  • 标准错误流stderr

所以我们要记得关闭文件

流  是一个抽象的概念 

IO文件流 : 输入流:数据从文件复制到内存的过程; 输出流:数据从内存保存到文件的过程。

在IO文件流中,是相对于计算机程序中的内存来说的 

3.操作文件的函数

 字符输入函数 fgetc的使用

int fgetc ( FILE * stream );

这里的 int 返回值 会接收到的内容,当遇到文件末尾,读取失败会返回EOF

#include<stdio.h>
int main()
{
	//使用fopen()打开文件
	FILE* pf = fopen("data.txt", "r");
	if (pf == NULL)
	{
		perror("fopen");
		return 1;
	}
	int ch = fgetc(pf);
	printf("%c\n",ch);
	ch = fgetc(pf);
	printf("%c\n", ch);
	//使用fclose()关闭文件
	fclose(pf);
	pf = NULL;
	return 0;
}

使用stdin  从键盘上读

#include<stdio.h>
int main()
{
	//使用fopen()打开文件
	FILE* pf = fopen("data.txt", "r");
	if (pf == NULL)
	{
		perror("fopen");
		return 1;
	}
	int ch = fgetc(stdin);
	printf("%c\n", ch);//从键盘上读
	ch = fgetc(stdin);
	printf("%c\n", ch);
	//使用fclose()关闭文件
	fclose(pf);
	pf = NULL;
	return 0;
}

 

 字符输入函数 fputc的使用

int fputc ( int character, FILE * stream );

#include<stdio.h>
int main()
{
	//使用fopen()打开文件
	FILE* pf = fopen("data.txt", "w");
	if (pf == NULL)
	{
		perror("fopen");
		return 1;
	}
	//写文件,写一个字符放到流中
	fputc('a',pf);
	fputc('c',pf);
	//使用fclose()关闭文件
	fclose(pf);
	pf = NULL;
	return 0;
}

打开文件查看

之前介绍的stdout 也可以不写入到文中,写入到屏幕上

#include<stdio.h>
int main()
{
	//使用fopen()打开文件
	FILE* pf = fopen("data.txt", "w");
	if (pf == NULL)
	{
		perror("fopen");
		return 1;
	}
	//写文件,写一个字符放到流中
	//stdout 写入到屏幕上
	fputc('a', stdout);
	fputc('c', stdout);
	//使用fclose()关闭文件
	fclose(pf);
	pf = NULL;
	return 0;
}

 上述是文件的顺序读写

 文本行输出函数  fputs()

从程序输出到文件中(写)

int fputs ( const char * str, FILE * stream );
#include<stdio.h>
int main() 
{
	FILE* pf = fopen("data.txt","w");
	if (pf == NULL) 
	{
		perror("fopen");
		return 1;
	}
	//写文件  一行的写
	fputs("hello\n",pf);
	fputs("world\n",pf);
	fclose(pf);
	pf = NULL;
	return 0;
}

文本行输入函数 fgets

char * fgets ( char * str, int num, FILE * stream );

要木遇到最多读n - 1 个,后面再追加一个'\0',要木遇到\n 不再读了

//一行的读
#include<stdio.h>
int main()
{
	FILE* pf = fopen("data.txt", "r");
	if (pf == NULL)
	{
		perror("fopen");
		return 1;
	}
	//读文件  一行的读
	char arr[10] = {0};
	fgets(arr,10,pf); //这里只读了9个. 要木遇到最多读n - 1 个,后面再追加一个'\0',要木遇到\n 不再读了
	printf("%s",arr);
	fclose(pf);
	pf = NULL;
	return 0;
}

格式化输出函数 fprintf()

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

Write formatted data to stream  写格式化数据到流里面去

#include<stdio.h>
struct S 
{
	int a;
	float b;
};
int main() 
{
	FILE* pf = fopen("data.txt","w");
	if (pf == NULL) 
	{
		perror("fopen");
		return 1;
	}

	//写文件 从程序中写入文件
	struct S s = {100,3.14f};
	fprintf(pf,"%d %f",s.a,s.b);

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

格式化输入函数 fscanf() 

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

Read formatted data from stream  把带有格式的数据从流里面读出

#include<stdio.h>
struct S
{
	int a;
	float b;
};
int main()
{
	FILE* pf = fopen("data.txt", "r");
	if (pf == NULL)
	{
		perror("fopen");
		return 1;
	}
	//读文件 把文件里面的数据读到程序里面去
	struct S s = {0};
	fscanf(pf,"%d %f",&(s.a),&(s.b));
	//这里把数据打印出来
	printf("%d %f",s.a,s.b);
	//这里把数据打印出来的第二种方式
	//fprintf(stdout,"%d %f",s.a,s.b);
	//关闭文件
	fclose(pf);
	pf = NULL;
	return 0;
}

区分:

// sprintf  和  sscanf  

#include<stdio.h>
struct S
{
	int a;
	float b;
	char str[10];
};
int main()
{
	char arr[30] = { 0 };
	struct S s = { 100,3.14f,"hello" };//将结构体里面的数据转换为字符串arr里面
	struct S tmp = {0};
	sprintf(arr, "%d %f   %s", s.a, s.b, s.str);//里面的空格也会转换到arr里面

	//从字符串中拿出格式化数据
	sscanf(arr,"%d %f %s",&(tmp.a),&(tmp.b),tmp.str);//从字符串arr中读取格式化数据
	printf("%d %f %s", tmp.a,tmp.b,tmp.str);
	return 0;
}

二进制输出 fwrite

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

#include<stdio.h>
struct S 
{
	int a;
	float b;
	char str[10];
};
int main() 
{
	struct S s = {100,3.14f,"zz"};
	FILE* pf = fopen("data.txt","wb");
	if (pf == NULL) 
	{
		perror("fopen");
		return 1;
	}

	//写文件
	fwrite(&s,sizeof(struct S),1,pf);

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

 打开文件 我们发现 看不明白(因为是二进制文件)

 可以使用fread 来读二进制文件

二进制输入 fread (从文件到内存)

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

Read block of data from stream 

//fread
#include<stdio.h>
struct S
{
	int a;
	float b;
	char str[10];
};
int main()
{
	struct S s = { 0 };
	FILE* pf = fopen("data.txt", "rb");
	if (pf == NULL)
	{
		perror("fopen");
		return 1;
	}

	//读文件
	fread(&s,sizeof(struct S),1,pf);
	//打印
	printf("%d %f %s",s.a,s.b,s.str);
	fclose(pf);
	pf = NULL;
	return 0;
}

四、文件的随机读写 

这里的文件随机读写 是 想读写哪里就读写哪里

 1.fseek

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

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

注意origin的参数

  •  SEEK_SET  从文件的起始位置开始
  •  SEEK_CUR   从当前所指向的位置开始
  •  SEEK_END   从文件的末尾开始  (注意从右向左 数字为负的)
//fseek的使用
#include<stdio.h>
int main() 
{
	FILE* pf = fopen("data.txt","r");
	//文件里面的内容为abcdefghi
	if (pf == NULL)
	{
		perror("fopen");
		return 1;
	}
	fseek(pf,3,SEEK_SET);//定位文件指针的指向,这里的正3表示从左到右
	int ch = fgetc(pf);
	printf("%c\n",ch);
	fclose(pf);
	pf = NULL;
	return 0;
}

图解 

2.ftell 

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

long int ftell ( FILE * stream );

//ftell返回文件指针相对于起始位置的偏移量
#include<stdio.h>
int main() 
{
	FILE* pf = fopen("data.txt","r");
	//文件内容是abcdefghi
	if (pf == NULL) 
	{
		perror("fopen");
		return 1;
	}
	int ch = fgetc(pf);
	printf("%c\n",ch);//a
	ch = fgetc(pf);
	printf("%c\n", ch);//b
	ch = fgetc(pf);
	printf("%c\n", ch);//c
	//用ret来接收偏移量
	int ret = ftell(pf);
	printf("%d\n",ret);//3  这里只适用于标准输出流(屏幕)
	fprintf(stdout,"%d",ret);//3 适用于所有的输出流
	fclose(pf);
	pf = NULL;
	return 0;
}

3.rewind 

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

void rewind ( FILE * stream );
//rewind 让文件指针的位置 回到 文件的起始位置
#include<stdio.h>
int main()
{
	FILE* pf = fopen("data.txt", "r");
	//文件内容是abcdefghi
	if (pf == NULL)
	{
		perror("fopen");
		return 1;
	}
	int ch = fgetc(pf);
	printf("%c\n", ch);//a
	ch = fgetc(pf);
	printf("%c\n", ch);//b
	ch = fgetc(pf);
	printf("%c\n", ch);//c
	//用ret来接收偏移量
	int ret = ftell(pf);
	printf("%d\n", ret);//3  这里只适用于标准输出流(屏幕)

	//使用rewind 回到起始位置
	rewind(pf);
	int a = ftell(pf);// 0
	fprintf(stdout,"%d",a);

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

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

文本文件 

如果要求在外存上以ASCII码的形式存储,则需要在存储前转换。以ASCII字符的形式存储的文件

二级制文件

数据在内存中以二进制的形式存储,如果不加转换的输出到外存 

例如 十进制的10000 看下方图解

 例如

#include<stdio.h>
int main() 
{
	int a = 10000;
	FILE* pf = fopen("data.txt","wb");
	if (pf == NULL) 
	{
		perror("fopen");
		return 1;
	}
	fwrite(&a,5,1,pf);//写到二进制文件中
	fclose(pf);
	pf = NULL;
	return 0;
}

我们已经把数据以二进制形式写入到文件中,但是当我们打开时发现

这是二进制文件,我们需要用特殊的编辑器来查看,就比如使用 Visual Studio 2022 来进行查看

下面是查看方法:

第一步  先 右击  源文件 - 添加 - 现有项

第二步 找到文本并添加进去

 这时就会看到

第三步   右击 文件 - 点击打开方式  

第四步 选择二进制编辑器

然后就有了 

六、文件读取结束的判定 

  •  fgetc  判断是否为EOF
  •  fgets 判断返回值是否为NULL
  •  fread 判断返回值是否小于实际要读的个数

在这里 要多说一个 feof

feof: 用于当文件读取结束的时候,判断是读取失败结束,还是遇到文件尾结束 

feof 用来判断是什么原因结束的

七、文件缓冲区 

文件缓冲区是指在操作系统中,将文件读取或写入时,先将数据缓存到内存中的一段空间,等待一定量的数据积累后再进行实际的读写操作。这样做的好处是可以提高文件输入和输出效率,减少文件系统的负担。而且通过缓冲,可以减少磁盘或网络的读写次数,降低系统负担,提高程序的性能。

文件缓冲区包括输入缓冲区和输出缓冲区。输入缓冲区用于存储等待处理的输入数据,而输出缓冲区用于存储等待写入文件的数据。当输入缓冲区或输出缓冲区已满或达到一定数量时,系统才会进行实际的读写操作。当文件操作完成时,缓冲区的内容会被写入或者读取出来,或者在程序运行结束时被自动释放。

在编程中,我们可以通过控制文件缓冲区大小和刷新缓冲区来提高程序效率。如果希望立即将缓冲区的数据写入磁盘或读取最新数据,可以使用flush()、fflush()等函数来强制刷新缓冲区。

#include<stdio.h>
#include<windows.h>
int main()
{
	FILE* pf = fopen("data.txt", "w");
	if (pf == NULL)
	{
		perror("fopen");
		return 1;
	}
	//
	fprintf(pf,"hello\n");
	fflush(pf);  //刷新后就会出现在文件中
	Sleep(10000);//睡眠10秒
	fprintf(pf,"world");
	fclose(pf);
	pf = NULL;
	return 0;
}

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

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

相关文章

awvs 中低危漏洞

低危 X-Frame-Options Header未配置 查看请求头中是否存在X-Frame-Options Header字段 会话Cookie中缺少secure属性(未设置安全标志的Cookie) 当cookie设置为Secure标志时&#xff0c;它指示浏览器只能通过安全SSL/TLS通道访问cookie。 未设置HttpOnly标志的Cookie 当cookie设置…

github小记(一):清除github在add或者commit之后缓存区

github清除在add或者commit之后缓存区 前言1. 第一步之后想要撤销2. 第二步之后想要撤销a. 改变一下rrr.txt的内容b. 想提交本地文件的test文件夹c. 我后悔了突然不想提交了 前言 github自用 一般github上代码提交顺序&#xff1a; 第一步&#xff1a; git add . or git ad…

好看的机制示意图绘制教程汇总

好看的机制示意图绘制教程汇总 蛋白翻译过程示意图&#xff0c;特别是其中的核糖体&#xff0c;需要很多绘制技巧。主要使用椭圆工具绘制两个椭圆&#xff0c;二者组合后使外形接近核糖体。接着通过路径查找器的合并功能&#xff08;并集&#xff09;将两个椭圆合并在一起。使…

linux--gdb的使用

1&#xff0c;Makefile默认release版本&#xff0c;要想进入debug版本需添加-g后缀 2&#xff0c;进入调试界面&#xff1a;gdb 可执行程序 3&#xff0c;显示代码&#xff1a;l&#xff08;list&#xff09; 数字&#xff08;1/0&#xff09; 不停回车可一直显示到结束并显…

CAS详解和学透面试必问并发安全问题

CAS&Atomic 原子操作详解 什么是原子操作&#xff1f;如何实现原子操作&#xff1f; 什么是原子性&#xff1f;相信很多同学在工作中经常使用事务&#xff0c;事务的一大特性就是原子性&#xff08;事务具有 ACID 四大特性&#xff09;&#xff0c;一个事务包含多个操作&a…

Zabbix监控系统 自定义监控项、自动发现与自动注册

Zabbix监控系统 自定义监控项、自动发现与自动注册 一、自定义监控内容部署实例二、zabbix 自动发现与自动注册部署实例2.1 部署zabbix自动发现 一、自定义监控内容部署实例 案列&#xff1a;自定义监控客户端服务器登录的人数 需求&#xff1a;限制登录人数不超过 3 个&#…

Jetpack:001-Jetpack概要介绍

文章目录 1. 概念介绍2. 主要内容2.1 框架库2.2 UI界面库 3. 核心思想4. 内容总结 本章回是一起Talk AndroidJetpack吧专栏的第一章回&#xff0c;本章回中主要介绍Jetpack的基本概念和编程思想&#xff0c;同时也会介绍它的基础知识。闲话休提&#xff0c;请我们一起Talk Andr…

【Vue面试题十三】、Vue中的$nextTick有什么作用?

文章底部有个人公众号&#xff1a;热爱技术的小郑。主要分享开发知识、学习资料、毕业设计指导等。有兴趣的可以关注一下。为何分享&#xff1f; 踩过的坑没必要让别人在再踩&#xff0c;自己复盘也能加深记忆。利己利人、所谓双赢。 面试官&#xff1a;Vue中的$nextTick有什么…

计算机视觉处理的开源框架

计算机视觉是一门涉及图像和视频分析的领域&#xff0c;有许多开源的框架和库可用于构建计算机视觉应用程序。以下是一些常见的计算机视觉开源框架及其特点&#xff0c;希望对大家有所帮助。北京木奇移动技术有限公司&#xff0c;专业的软件外包开发公司&#xff0c;欢迎交流合…

GNU和Linux的关系、 Linux的发行版本、CentOs和RedHat的区别

GNU和Linux的关系 其实&#xff0c;我们通常称之为的"Linux"系统&#xff0c;相对更准确的名称应该称为“GNU/Linux”系统&#xff01; 一个功能完全的操作系统需要许多不同的组成部分&#xff0c;其中就包括内核及其他组件&#xff1b;而在GNU/Linux系统中的内核就…

什么是成分分析?成分分析检测包括哪些?

成分分析:指通过微观谱图及激光飞秒检测方法对产品或样品的成分进行分析&#xff0c;对各个成分进行定性定量分析的技术方法。 成分分析技术主要用于对未知物、未知成分等进行分析&#xff0c;通过成分分析技术可以快速确定(最快的为激光飞秒检测通过观测分子、原子、电子、原…

【Mybatis源码】IDEA中Mybatis源码环境搭建

一、Mybatis源码源 在github中找到Mybatis源码地址&#xff1a;https://github.com/mybatis/mybatis-3 找到Mybatis git地址 二、IDEA导入Mybatis源码 点击Clone下载Mybatis源码 三、选择Mybatis分支 选择Mybatis分支&#xff0c;这里我选择的是3.4.x分支

点云分割segmentation

点云分割是根据空间、几何和纹理等特征对点云进行划分&#xff0c;使得同一划分区域内的点云拥有相似的特征 。点云的有效分割往往是许多应用的前提。例如&#xff0c;在逆向工程CAD/CAM 领域&#xff0c;对零件的不同扫描表面进行分割&#xff0c;然后才能更好地进行孔洞修复、…

Yocto Project 编译imx-第1节(下载和编译)

Yocto Project 编译imx-第1节&#xff08;下载和编译&#xff09; 前言说明参考文章版本说明Ubuntu 系统说明和建议必备软件安装设置Git用户名和密码解决git报错使用FastGithub 获取repo获取Yocto项目设置Yocto源获取Yocto版本&#xff08;https://source.codeaurora.org废弃&a…

【C++从0到王者】第三十六站:哈希

文章目录 一、unordered系列容器二、unordered_set三、unordered_map四、unordered_set与set的比较五、各种查找的比较六、哈希函数1.哈希函数概念与哈希冲突2.常见哈希函数 七、解决哈希冲突1.闭散列---开放定址法2.开散列---拉链法/哈希桶 一、unordered系列容器 在C98中&…

在校大学生想从事网络安全工程师,来听听过来人的经验,你会少走很多弯路

大家好&#xff01;一直以来都有一些大学生粉丝私聊向我“取经”&#xff0c;可以看得出来很多人对前路多多少少都有些迷茫&#xff0c;我把大家的问题总结了一下&#xff0c;并对每个问题都做了我自己的见解&#xff0c;高频出现的问题有以下几个&#xff1a; 1.国内程序员的…

算法错题簿(持续更新)

自用算法错题簿&#xff0c;按算法与数据结构分类 python1、二维矩阵&#xff1a;记忆化搜索dp2、图论&#xff1a;DFS3、回溯&#xff1a;129612964、二叉树&#xff1a;贪心算法5、字符串&#xff1a;记忆化搜索6、01字符串反转&#xff1a;结论题7、二进制数&#xff1a;逆向…

车载通信架构 —— DDS协议介绍

车载通信架构 —— DDS协议介绍 我是穿拖鞋的汉子&#xff0c;魔都中坚持长期主义的汽车电子工程师。 老规矩&#xff0c;分享一段喜欢的文字&#xff0c;避免自己成为高知识低文化的工程师&#xff1a; 屏蔽力是信息过载时代一个人的特殊竞争力&#xff0c;任何消耗你的人和…

如何实现mac系统远程控制window

Mac和Windows是两个广泛使用的操作系统&#xff0c;它们有着各自的特点和优势。有时候&#xff0c;可能需要在Mac系统上进行工作&#xff0c;但仍然需要远程访问和控制Windows系统。幸运的是&#xff0c;有几种方法可以实现这一目标。 一、远程桌面协议&#xff08;RDP&#xf…

yarn 安装、常用命令、与npm命令区别

一、下载安装 npm install yarn tyarn -g安装完成之后检查版本 yarn --version // 1.22.17linux环境下可以配置yarn的软链 ln -s /usr/local/nodejs/node-v16.16.0-linux-x64/bin/yarn /usr/local/bin/二、配置Yarn 配置源 # tuonioooo yarn config set registry https://…