重温文件操作(一)

2023/9/30 17:04:30

目录

什么是文件?

 文件名:

 文件指针:

 fopen函数:

fclose:

 文件的顺序读写:

fputc:

fgetc

fputs

fgetc

fprintf

 fscanf

对流的解释:

二进制输出fwrite

fread

 sprintf


什么是文件?

 

 文件名:

 文件指针:

 

 文件指针就指向了文件信息区,文件信息区是一个结构体,里面存储的有文件信息区的数据。

我们举一个例子:

当我们打开一个test.txt的文件时:

 当我们打开文件test.txt时,我们会创建一个文件信息区,同时产生一个文件指针pf,该文件指针pf指向文件信息区,通过文件信息区的内容就能够访问该文件,也就是说,通过文件指针可以访问对应的文件。

 fopen函数:

 该函数的作用是打开文件,第一个参数表示打开的文件的文件名,第二个参数表示打开文件的方式。

 第二个参数可以是以上的这些:“r"表示以读的形式,当我们以读的形式打开文件时,文件需要存在,否则会打开失败。

"w"表示以写的形式打开文件,文件不需要存在。

其他的四个我们不需要了解。

当成功打开时,我们返回指向该文件的文件信息区的文件指针,当打开失败的时候,我们返回空指针。

实验:

#include<stdio.h>
#include<errno.h>
#include<string.h>
int main()
{
	FILE*pf = fopen("test.txt", "r");
	if (pf == NULL)
	{
		printf("%s\n", strerror(errno));
		return 1;
	}
	return 0;
}

 让我们对代码进行逐语句分析:

这串代码的意思是:首先,以读的形式打开文件test.txt,并返回指向该文件信息区的文件指针,但是打开文件可能会失败,所以我们要进行检测:我们判断pf是否为空指针,假如pf为空指针,证明我们打开文件失败,errno表示错误码,strerror表示把错误码转换成对应的错误信息,这里的意思是假如打开文件失败,我们把对应的错误码转换为错误信息并打印出来,当打开失败时,我们直接return 1退出文件。

fclose:

 fclose函数的意思是:关闭文件。

每次打开或使用文件后,当我们要退出时,我们都需要关闭该文件,在这里就相当于资源的释放。

int main()
{
	FILE*pf = fopen("test.txt", "r");
	if (pf == NULL)
	{
		printf("%s\n", strerror(errno));
		return 1;
	}
	fclose(pf);
	pf = NULL;
	return 0;
}

每次fclose之后都需要把pf指针置为空指针。

#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
#include<errno.h>
#include<string.h>
int main()
{
	FILE*pf = fopen("test.txt", "r");
	if (pf == NULL)
	{
		printf("%s\n", strerror(errno));
		return 1;
	}
	fclose(pf);
	pf = NULL;
	return 0;
}

我们进行运行:

表示没有文件或目录。

但是假如我们在对应代码的目录下创建一个文件,这时候我们再调用代码:

这时候就不会报错了。

 文件的顺序读写:

 我们对输入流输出流的概念进行解析:

 我们写的代码首先是加载到内存中的,假如我们想把我们写的代码或者数据加载到显示器或者硬盘中去,我们可以把代码先加载到输出流,再由输出流进行加载,这样可以简化我们程序员的工作和学习容量。

输入和输出:输入和输出是针对内存的,输出表示从内存中输出到硬件中,输入表示从硬件输入到内存中去。

fputc:

 表示输出字符到流中(写字符到流中)

例如:

int main()
{
	FILE*pf = fopen("test", "w");
	if (pf == NULL)
	{
		printf("%s\n", strerror(errno));
		return 1;
	}
	fputc('a', pf);
	fclose(pf);
	pf = NULL;
	return 0;
}

我们以写的形式打开文件test,假如没有,我们会自定创建test

然后我们往文件中输入'a'。

我们打开test文件,发现test的内容是a,证明我们输出成功。

我们再举一个例子:

int main()
{
	FILE*pf = fopen("test", "w");
	if (pf == NULL)
	{
		printf("%s\n", strerror(errno));
		return 1;
	}
	/*fputc('a', pf);*/
	for (int i = 'a'; i <='z' ; i++)
	{
		fputc(i, pf);
	}
	fclose(pf);
	pf = NULL;
	return 0;
}

我们输出a到z26个字符到文件test中

我们的文件test中的内容就变成了a到z

 我们第一次执行写入的是‘a',显示的也是‘a’,第二次执行写入的是’a‘到’z',写入的也是‘a’到‘z’

证明我们每一次执行写入并且不在同一个程序中时,我们会对文件中的内容进行刷新重置。

fgetc

 这里的意思是从文件中取字符。

例如:

int main()
{
	FILE*pf = fopen("test", "r");
	if (pf == NULL)
	{
		printf("%s\n", strerror(errno));
		return 1;
	}
	int ch = fgetc(pf);
	printf("%c\n", ch);
	ch = fgetc(pf);
	printf("%c\n", ch);
	fclose(pf);
	pf = NULL;
	return 0;
}

我们进行运行。

 

 注意:当我们要进行读的操作的时候,我们需要修改foepn的参数'w'修改成为'r'。

并且我们连续读时,我们会进行顺序读。

接下来,我们来看fget的返回值:

 当调用成功的时候,返回元素本身,当调用失败或访问到文件末尾时,我们返回eof。

所以完美的写法是这样:

int main()
{
	FILE*pf = fopen("test", "r");
	if (pf == NULL)
	{
		printf("%s\n", strerror(errno));
		return 1;
	}
	
	int ch = 0;
	while ((ch = fgetc(pf)) != EOF)
	{
		printf("%c ", ch);
	}
	fclose(pf);
	pf = NULL;
	return 0;
}

fputs

 写一行数据到流中(文件中)

例如:

int main()
{
	FILE*pf = fopen("test", "w");
	if (pf == NULL)
	{
		printf("%s\n", strerror(errno));
		return 1;
	}
	fputs("hello world", pf);
	fclose(pf);
	pf = NULL;
	return 0;
}

我们打开文件查看

 我们成功把字符串hello world写入到了文件里面。

当我们想要追加时,我们可以这样写:

 我们进行运行:

 这里就出现了两个hello world

fgetc

从文件中读一行数据

例如:

int main()
{
	FILE*pf = fopen("test", "r");
	if (pf == NULL)
	{
		printf("%s\n", strerror(errno));
		return 1;
	}
	char arr[20] = { 0 };
	fgets(arr, 12, pf);
	for (int i = 0; i < 12; i++)
	{
		printf("%c ", arr[i]);
	}
	fclose(pf);
	pf = NULL;
	return 0;
}

 表示从文件pf中读取12个字符的数据,读取到数组arr中

然后我们循环打印数组arr。

 注意:我们读取的12个字符中有一个是'\0',所以我们读取的有效字符只有11个。

接下来,我们查看一下fgets的返回值:

 调用成功时,返回字符串,调用失败时,返回空指针。

fprintf

 写格式化数据到字符串中。

假如我们要打印结构体中的数据,我们该如何打印呢?

struct S
{
	char arr[10];
	int age;
	float score;
};
int main()
{
	struct S s = { "zhangsan", 25, 50.5f };
	FILE*pf = fopen("test", "w");
	if (pf == NULL)
	{
		perror("fopen");
		return 1;
	}
	printf("%s %d %f", s.arr, s.age, s.score);
fclose(pf);
	pf = NULL;
	return 0;
}

假如我们要把这些结构体的数据写入到文件中,我们可以使用fprintf

struct S
{
	char arr[10];
	int age;
	float score;
};
int main()
{
	struct S s = { "zhangsan", 25, 50.5f };
	FILE*pf = fopen("test", "w");
	if (pf == NULL)
	{
		perror("fopen");
		return 1;
	}
	fprintf(pf,"%s %d %f", s.arr, s.age, s.score);
fclose(pf);
	pf = NULL;
	return 0;
}

我们打开文件进行查看

 fscanf

从文件中读取格式化数据。

例如:我们现在文件中的内容是这样:

我们想要把文件中的数据读取到内存中去。

struct S
{
	char arr[10];
	int age;
	float score;
};
int main()
{
	struct S s = { 0 };
	FILE*pf = fopen("test", "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);
	fclose(pf);
	pf = NULL;
	return 0;
}

我们创建一个空结构体,然后从从文件指针pf中,读取三个不同类型的数据到结构体中,然后我们打印结构体,打印的结果如图所示:

 证明我们读取成功。

对流的解释:

 我们的写(输出)和读(输入)都是针对内存的,从内存中输出文件到硬盘中,从硬盘中输入文件到内存中。

 计算机分为内部设备和外部设备,内存设备就是内存,外部设备有很多,例如屏幕 网络 u盘 硬盘等等,我们从内存写入到不同的外部设备的方法也是不同的,但是为了简化程序员的学习成本,我们设计了流,流是一种媒介,对于不同设备之间的输入和输出,流可以自动调节,我们只需要实现数据的输入和输出即可,不需要考虑不同设备之间的不同方法。

二进制输出fwrite

 写二进位制数据到文件中。

struct S
{
	char arr[10];
	int age;
	float score;
};
int main()
{
	struct S s = { "zhangsan",25,50.5f };
	FILE*pf = fopen("test", "wb");
	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);

	fwrite(&s, sizeof(s), 1, pf);
	fclose(pf);
	pf = NULL;
	return 0;
}

我们创建一个结构体,结构体中有三个不同类型的数据,我们以二进位制写的形式打开文件pf,然后我们以二进位制的形式,从s的地址中,取sizeof(s)个字节的数据,取1个,写入到文件指针指向的文件中去。

我们进行运行:

 看不懂的原因是普通类型转化为二进位制,zhangsan能够看懂的原因是我们以文本的形式放进去和二进位制的形式放进文件中显示的结果是相同的。

fread

 从文件中读取二进位制数据:

struct S
{
	char arr[10];
	int age;
	float score;
};
int main()
{
	struct S s = {0};
	FILE*pf = fopen("test", "wr");
	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);
	/*fwrite(&s, sizeof(s), 1, pf);*/
	fread(&s, sizeof(s), 1, pf);
	printf("%s %d %f", s.arr, s.age, s.score);
	fclose(pf);
	pf = NULL;
	return 0;
}

我们进行编译:

 sprintf

 

 写格式化数据到字符串中。

例如:

struct S
{
	char arr[10];
	int age;
	float score;
};
int main()
{
	struct S s = { "zhangsan", 20, 50.5f };
	char buf[100] = { 0 };
	sprintf(buf, "%s %d %f", s.arr, s.age, s.score);
	printf("%s\n", buf);
	return 0;
}

这串代码的意思是:我们创建一个结构体对象s,然后创建一个数字,我们使用sprintf,把结构体s的对象中的数据格式化输出到buf中,本质上是把格式化数据转换为字符串。

我们进行打印:

 从字符串中读取格式化数据。

例如:

struct S
{
	char arr[10];
	int age;
	float score;
};
int main()
{
	struct S s = { "zhangsan", 20, 50.5f };
	char buf[100] = { 0 };
	sprintf(buf, "%s %d %f", s.arr, s.age, s.score);
	/*printf("%s\n", buf);*/
	struct S tmp = { 0 };
	sscanf(buf, "%s %d %f", tmp.arr, &tmp.age, &tmp.score);
	printf("%s %d %f", tmp.arr, tmp.age, tmp.score);
	return 0;
}

这串代码的意思是:我们首先创建一个结构体,创建一个空数组,我们使用sprintf函数把格式化数据写入到字符串buf中,然后我们再使用scanf,把字符串中的数据获取格式化数据到结构体tmp中。

总结:sprintf表示把格式化数据写入到字符串

sscanf表示从字符串中获取格式化数据 

fseek

对指针进行重定向

三个参数分别表示

 第一个参数表示文件指针,第二个参数表示偏移量(相对于第三个参数),第三个参数表示指针的三个位置,分别是文件的开头,指针的当前位置和文件的末尾。

 ftell

 得到相对于起始位置的偏移量。

 

 


http://www.jnnr.cn/a/129332.html

相关文章

数据结构和算法 II

数据结构和算法 II 面试题 (1) 用户表中添加一条数据,请写出SQL语句 insert into user values(1,tom,男,23,2022-12-12,1)(2) 在用户表中把姓名为"李四"的在职用户的年龄修改为28 update user set age28,sex女 where name李四 and state1(3) 查询所有的角色名称为…

Feign 实现 GET 方法传递 POJO

Feign 实现 GET 方法传递 POJO 作者&#xff1a;Grey 原文地址&#xff1a; 博客园&#xff1a;Feign 实现 GET 方法传递 POJO CSDN&#xff1a;Feign 实现 GET 方法传递 POJO 需求 Spring MVC 支持 GET 方法直接绑定 POJO 的&#xff0c;但是 Feign 目前无法做到&#x…

与Cartesi 技术社区经理Shaheen 的 AMA 回顾

关于 Cartesi Rollups 测试网 Alpha和后续步骤的一些问题已经得到解答如果你不是开发人员&#xff0c;你可能对我们在Cartesi构建的内容有很多疑问。幸运的是&#xff0c;我们团队有很多可以解释技术问题的人。像你这样对区块链和Web3面向未来感到兴奋和热情的人&#xff0c;将…

嵌入式分享合集100

终于写到100集了~~ 一、实时操作系统 想象这样一个场景&#xff1a;周五&#xff0c;结束了一周忙碌的工作&#xff0c;回到家&#xff0c;防盗门仿佛是认识你一般自动打开&#xff0c;进到屋中&#xff0c;电灯自动打开&#xff0c;色温和亮度都刚刚好&#xff0c;地板早已被…

【深入浅出Spring6】第二期——依赖注入

一、 IoC 控制反转 控制反转是一种思想&#xff0c;依赖注入是其具体实现【Dependence Injection】控制反转的目的&#xff1a;为了降低程序的耦合度&#xff0c;提高程序的可扩展力&#xff0c;进而使程序满足开闭原则和依赖倒置原则控制反转的主要工作&#xff1a; 通过第三…

c++的作用域 (局部域,类域,名字命名空间,文件域)

这里写目录标题局部域类域类修饰指针由类限制修饰指向变量的指针由类修饰指向函数的指针命名空间背景&#xff1a;文件域c支持四个域&#xff1a;局部域&#xff0c;类域&#xff0c;名字空间域&#xff0c;文件域局部域 函数域 这两个a就处于不同的局部域中 局部块域 这两个…

猿创征文|工具百宝箱-数据库连接工具-接口调试与测试工具-抓包工具

工具没有绝对意义上的好坏之分&#xff0c;只有需求适合与否&#xff0c;这些需求可能包括&#xff1a;功能、价格、安全、服务、技术等诸多方面。 技术在更新迭代&#xff0c;开发者工具也在更新迭代。一个高效趁手的工具在工作上锦上添花。给大家分享一下我平时用的一部分工…

【面试题】给你一个项目,你准备怎么开展ui自动化

给你一个项目&#xff0c;你准备怎么开展ui自动化 面试官这么问&#xff0c;基本上就是真的公司内有一个项目等着你开展自动化了。所以&#xff0c;在他们面试的很多人中都会问这样的一个问题&#xff0c;想看看谁的方案和策略最靠谱。而这时&#xff0c;你就应该明白&#xf…

功能寻址的注意事项

诊断协议那些事儿 本文为诊断协议那些事儿专栏文章&#xff0c;在前文诊断的寻址方式中提及功能寻址的概念&#xff0c;整车上的ECU&#xff0c;响应诊断服务请求&#xff0c;每一个具备uds诊断功能的ecu&#xff0c;都具有三个特殊的can id&#xff0c;分别为功能寻址和物理寻…

什么是 ABC NFT 系列?

Nov. 2022, Vincy Data Source: Footprint Analytics - ABC NFT Collection ABC&#xff08;Abracadabra&#xff09;是 HGE.SOL 在 8 月 23 日推出的 NFT 系列。该系列以儿童卡通涂鸦模式绘制&#xff0c;“让您想起我们小时候&#xff0c;长大之前的乐趣。” ABC 初始铸造价…

【Unity3D】资源文件 ② ( Unity 中场景文件简介 | 查看场景文件内容 | 场景文件相关操作 | 创建场景 | 打开场景 )

文章目录一、Unity 中场景文件简介二、查看场景文件内容三、场景文件相关操作1、添加场景2、打开场景一、Unity 中场景文件简介 Unity 编辑器中的 场景文件 是以 " .unity " 为后缀的文件 , 该文件中会记录所有 游戏物体 GameObject , 以及游戏物体的相关数据 , 如下…

Android开发之——Jetpack Compose布局(03)

一 概述 布局基础知识ConstraintLayout布局Material 组件和布局自定义布局构建自适应布局Jetpack Compose 中的对齐线固有特性测量 二 布局基础知识 Column &#xff1a;将多个项垂直地放置在屏幕上Row&#xff1a;将多个项水平地放置在屏幕上Box &#xff1a;将元素放在其他…

极智AI | 谈谈昇腾 CANN AIPP

欢迎关注我的公众号 [极智视界]&#xff0c;获取我的更多笔记分享 大家好&#xff0c;我是极智视界&#xff0c;本文介绍一下 谈谈昇腾 CANN AIPP。 昇腾 CANN 的全称是 Compute Architecture for Neural Networks&#xff0c;是昇腾针对 AI 场景推出的异构计算架构。前几天写了…

Nacos——配置中心源码详解

Nacos——配置中心源码详解配置中心客户端主动获取客户端服务端客户端长轮询更新客户端1.入口2.配置文件分片处理3.配置文件处理4.本地配置文件与缓存数据的对比5.开启长轮询与服务端对比6.通知监听器7.监听回调处理服务端1.入口2.长轮询机制3.长轮询的延迟任务4.数据变更事件总…

只需三步,教你搭建一个进销存管理系统!

如果你常常面临&#xff1a;进销存软件功能不全、功能冗余、价格昂贵&#xff0c;性价比不高的情况—— 可以考虑使用【零代码搭建】了&#xff01; 在简道云可以根据自身需求快速搭建出进销存管理系统。相比较其他标准进销存软件&#xff0c;用简道云搭建进销存具备以下优势…

Qt .pro和.qrc创建及介绍

一、.pro文件创建及介绍 一般情况下&#xff0c;在vs中新建的Qt项目是没有.qrc文件的&#xff0c;这时我们可以点击上方的Qt VS Tools,如下图所示&#xff0c;选择Create Basic .pro File,便可以生成.pro文件。 ​后缀为.pro的文件是项目的管理文件&#xff0c;它主要用于记录…

Thread线程初识

目录多线程程序和线程核心概念线程创建Thead类测试Runnable 接口--推荐使用&#xff1a;java单继承的局限性测试Callable 接口测试并发测试Lamda表达式优点本质Lambda由来匿名内部类升级版-->lambdaLambda 简化写法去掉参数类型去掉小括号去掉花括号线程状态线程停止线程休眠…

CSS实现背景图片模糊——毛玻璃效果 | 浅谈CSS属性 filter、backdrop-filter

&#x1f4ad;&#x1f4ad; ✨&#xff1a; CSS实现背景图片模糊——毛玻璃效果 | 浅谈CSS属性 filter、backdrop-filter   &#x1f49f;&#xff1a;东非不开森的主页   &#x1f49c;: 因为很多东西来不及去做去看可是时间很快总是赶不上&#xff0c;所以要去成长呀&…

R语言七天入门教程五:认识并使用函数

R语言七天入门教程五&#xff1a;认识并使用函数 一、什么是函数 在编程语言中&#xff0c;如果有一段代码需要在多次重复使用&#xff0c;除了复制粘贴外&#xff0c;还可以将其写成一个函数。函数可以很方便地实现代码复用&#xff0c;对于复杂的程序功能&#xff0c;可以将…

ASM 字节码插桩 :线程治理

1.面临的挑战 对于开发者来说&#xff0c;线程治理一直是比较棘手的问题。主要有以下两个问题 大量的匿名线程。new Thread 的方式虽然可以实现快速、优先级最高的异步化&#xff0c;然而过多的匿名线程对于问题排查难度、稳定性都是一种挑战空闲线程得不到释放。经过业务的快…
最新文章