【C/C++进阶】——文件操作之文本文件与二进制文件指针读写

news2024/9/22 13:33:14

【文件】——操作文件

目录

一:文件的定义

二:文件名

三:文件类型

3.1:二进制文件

3.2:文本文件

四:文件的打开与关闭

4.1:文件指针

4.2:文件的打开与关闭

五:文件的顺序读写

5.1:读写字符

5.2:读写字符串

5.3:读写格式化数据

六:文件的随机读写

6.1:fseek

6.2:ftell

6.3:rewind

七:文件读取结束的判定

八:文件缓冲区(处理数据文件的本质)


一:文件的定义

所谓文件就是:磁盘上的文件。

在程序设计中,我们主要说的文件一般分为两种:1.程序文件;2.数据文件。

程序文件:字面意思,就是在写程序的过程中所写出的文件。包括源程序文件(后缀为 .c),目标文件(后缀为 .obj),可执行程序文件(后缀为 .exe)等等。

数据文件:文件中的内容不一定是程序,而是程序在运行时所读写的数据,例如程序运行过程中需要从中读取数据的文件,或输出内容的文件。

所谓的操作文件实际上操作的就是 数据文件。 

操作数据文件:写程序时,把信息输出到磁盘上,当有需要的时候再从磁盘上将数据读取到内存中使用。即处理磁盘上的文件。

二:文件名

当我们操作某一数据文件时,需要将该文件所处的目录”拿出来“。也就是说一个文件要有一个唯一的文件标识,以便用户们识别和引用。

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

例如:D:\code\gitee-main\main_-c\2024-5-22文件操作\test.txt

为了方便起见,文件标识也常被称为文件名。 

三:文件类型

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

3.1:二进制文件

二进制文件:数据以二进制的形式存储在文件中。

总的来说,二进制文件中的内容就是我们看不懂的文件。  

3.2:文本文件

文本文件:数据在外存上以ASCII码的形式存储的文件。

 文本文件就是我们能看的懂的文件。

四:文件的打开与关闭

在学习文件的打开与关闭之前,这必然要先了解学习一下文件指针。

4.1:文件指针

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

        每当打开一个文件的时候,系统会根据文件的情况自动创建一个FILE结构的变量,并填充其中的信息。

         一般都是通过一个FILE的指针来维护这个FILE结构的变量,这样使用起来更加方便。创建一个 FILE* 的指针变量。

FILE* pf;    // 创建一个文件指针变量

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

4.2:文件的打开与关闭

程序中是如何对文件进行打开与关闭的呢?

以喝一瓶水为例:第一步,打开水瓶;第二步,喝水;第三步,关闭水瓶。

同理文件操作:第一步,打开文件;第二步,读/写文件;第三步,关闭文件。

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

打开文件:

关闭文件:

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

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

//关闭文件
int fclose(FILE* stream)

其中,fopen函数中的 mode 指的是文件的打开方式:

文件使用打开方式含义若指定文件不存在
" r "(只读)为了输入数据,打开一个已经存在的文本文件出错
“w”(只写)为了输出数据,打开一个文本文件建立一个新的文件
“a”(追加)向文本文件尾添加数据出错
“rb”(只读)为了输入数据,打开一个二进制文件出错
“wb”(只写)为了输出数据,打开一个二进制文件建立一个新的文件
 
FILE* pf = fopen("test.txt", "r");    // 从文件中读取数据
FILE* pf = fopen("test.txt", "w");    // 写数据到文件中
FILE* pf = fopen("test.txt", "a");    // 写数据到文件末尾
FILE* pf = fopen("test.txt", "rb");   // 从二进制文件中读取数据
FILE* pf = fopen("test.txt", "wb");   // 写数据到二进制文件中

先看一个例子代码:

#include<stdio.h>

int main()
{
    // 打开文件
	FILE* pf = fopen("test.txt", "r");
	if (pf == NULL)
	{
		perror("fopen fail");
		return;
	}

	// 读字符
	int ch = 0;
	while ((ch = fgetc(pf)) != EOF)
	{
		printf("%c", ch);
	}

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

// 打印结果:hello china

五:文件的顺序读写

顺序读写:在读取遍历文件中的数据时一个接着一个的读取,是有顺序的读写。

读写文件的思维导图 :

5.1:读写字符

读字符:

写字符:

// 读函数使用形式:
int fgetc ( FILE * stream );

// 写函数使用形式:
int fputc ( int character, FILE * stream );



// stream:所操作的文件指针
// character:写入文件的字符

 写数据到文件中:

#include<stdio.h>

int main()
{
	// 写字符到文件中
	FILE* pf = fopen("test.txt", "w");
	if (pf == NULL)
	{
		perror("fopen fail");
		return;
	}
	fputc('a', pf);
	fputc('b', pf);
	fputc('c', pf);

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

程序运行前:

 程序运行后:

读文件中的数据:

#include<stdio.h>

int main()
{
	// 读文件中的数据
	FILE* pf = fopen("test.txt", "r");
	if (pf == NULL)
	{
		perror("fopen fail");
		return;
	}

	int ch = 0;
	ch = fgetc(pf);
	printf("%c", ch);
	ch = fgetc(pf);
	printf("%c", ch);
	ch = fgetc(pf);
	printf("%c", ch);

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

程序运行结果:

5.2:读写字符串

读写字符串函数使用形式:

// 读字符串
char * fgets ( char * str, int num, FILE * stream );
// str:将从文件中所读的数据放入到一个数组中
// num:从文件中读取num个字符
// stream:所操作的文件指针



// 写字符串
int fputs ( const char * str, FILE * stream );
// str:将str数组中的内容写入到文件中
// stream:所操作的文件指针

写字符串数据

代码实例:

#include<stdio.h>

int main()
{
	// 写字符串数据到文件中
	char arr[] = "abcdefghi";
	FILE* pf = fopen("test.txt", "w");
	if (pf == NULL)
	{
		perror("fopen fail");
		return;
	}

	// 写数据
	fputs(arr, pf);

	fclose(pf);
	pf = NULL;
    return0;
}

 程序运行前:

 程序运行后:

读字符串数据

代码实例:

#include<stdio.h>

int main()
{
	// 读文件中的数据
	char arr1[30] = { 0 };
	FILE* pf = fopen("test.txt", "r");
	if (pf == NULL)
	{
		perror("fopen fail");
		return;
	}

	// 读数据
	fgets(arr1, 10, pf);
	printf("arr1 = %s\n", arr1);

	fclose(pf);
	pf = NULL;
}

程序运行结果:

5.3:读写格式化数据

// 读格式化数据
int fscanf ( FILE * stream, const char * format, ... );


// 写格式化数据
int fprintf ( FILE * stream, const char * format, ... );

写格式化数据

 代码实例:

#include<stdio.h>

// 读写格式化数据
struct Stu
{
	char name[20];	// 姓名
	int age;		// 年龄
	char sex[5];	// 性别
};

int main()
{
	// 写格式化数据
	struct Stu s = { "张三",21,"男" };

	FILE* pf = fopen("test.txt", "w");
	if (pf == NULL)
	{
		perror("fopen fail");
		return;
	}

	// 写:
	fprintf(pf, "%s %d %s", s.name, s.age, s.sex);

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

程序运行结果前:

程序运行结果后: 

读格式化数据

代码实例:

#include<stdio.h>

// 读写格式化数据
struct Stu
{
	char name[20];	// 姓名
	int age;		// 年龄
	char sex[5];	// 性别
};

int main()
{
	// 读文件中的数据
	struct Stu s1 = { 0 };

	FILE* pf = fopen("test.txt", "r");
	if (pf == NULL)
	{
		perror("fopen fail");
		return;
	}

	// 读
	fscanf(pf, "%s %d %s", s1.name, &(s1.age), s1.sex);
	printf("%s %d %s", s1.name, s1.age, s1.sex);

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

运行结果:

六:文件的随机读写

随机读写:读取文件信息时并不是一个接着一个来读取的,是随机的,不固定的。

文件的随机读写有三个函数来操作:

// 1.fseek
// 根据文件指针的位置和偏移量来定位文件指针
int fseek ( FILE * stream, long int offset, int origin );
// offset:偏移量
// origin:相对位置


// 2.ftell
// 返回文件指针相对于起始位置的偏移量
long int ftell ( FILE * stream );

// 3.rewind
// 让文件指针的位置回到文件的起始位置
void rewind ( FILE * stream );

6.1:fseek

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

int fseek ( FILE * stream, long int offset, int origin );
// offset:偏移量
// origin:相对位置

6.2:ftell

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

当不知道文件指针在哪个位置时,可以通过 ftell 函数来知道该指针的位置。

6.3:rewind

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

七:文件读取结束的判定

我们在在学习的过程中,可能会遇到一些函数来判断文件是否结束,例如:feof函数。

但是,在文件读取过程中,不能用feof函数的返回值直接用来判断文件的是否结束。而是应用于当文件读取结束的时候, 判断是读取失败结束,还是遇到文件尾结束。文本文件读取是否结束, 判断返回值是否为EOF (fgetc),或者NULL(fgets)
例如:
 
  • fgetc判断是否为EOF.
  • fgets判断返回值是否为NULL

八:文件缓冲区(处理数据文件的本质)

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

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

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

相关文章

【Stable Diffusion】ComfyUI-插件-IPAdapter图片融合

哈喽大家好&#xff0c;这期来分享下如何利用IPAdapter实现两张图的融合 参考图1 参考图2 融合图 图片融合 1、工作流 将基础工作流中的【IPAdapter Unified Loader】节点换成【IPAdapter Unified Loader Community】 【IPAdapter】节点换成【IPAdapter advanced】 【IPAd…

C语言指针详解(1)

目录 一、什么是指针 1.1、定义 1.2、取地址操作符&#xff08;&&#xff09; 1.3、指针变量和解引用操作符&#xff08;*&#xff09; 二、指针变量类型的意义 三、const修饰指针 3.1、const修饰变量 3.2、const修饰指针变量 3.2.1、const放在*的左边 3.2.2、 con…

docker的安装+docker镜像的基本操作

一&#xff0e;docker的介绍 1、Docker 是什么&#xff1f; Docker 是⼀个开源的应⽤容器引擎&#xff0c;可以实现虚拟化&#xff0c;完全采⽤“沙 盒”机制&#xff0c;容器之间不会存在任何接⼝。 Docker 通过 Linux Container&#xff08;容器&#xff09;技术将任意…

中秋节送礼推荐,数码好物精选推荐

中秋节将至&#xff0c;想要为家人或朋友准备一份特别的礼物吗&#xff1f;不妨考虑南卡Runner Pro5骨传导耳机。这款耳机不仅在功能上表现出色&#xff0c;而且设计独特&#xff0c;非常适合作为节日赠品。 卓越的性能&#xff0c;完美的体验 南卡Runner Pro5凭借其卓越的性…

移情别恋c++ ദ്ദി˶ー̀֊ー́ ) ——7.list(模拟实现)

1.前言 1.1list与vector的不同 区别&#xff1a;list的迭代器底层和其他两个迭代器底层有很大区别&#xff0c;因为list的链式结构决定了与它们两个的不一样 相同&#xff1a;迭代器用法大致一样&#xff0c;其他成员函数的使用也大致一样。 vector与list都是STL中非常重要的序…

关于安装hbase的问题(操作系统-windows)

&#x1f3c6;本文收录于《CSDN问答解惑-专业版》专栏&#xff0c;主要记录项目实战过程中的Bug之前因后果及提供真实有效的解决方案&#xff0c;希望能够助你一臂之力&#xff0c;帮你早日登顶实现财富自由&#x1f680;&#xff1b;同时&#xff0c;欢迎大家关注&&收…

快速学习“堆“排序(C语言数据结构)

前言&#xff1a; 堆的实现其实并不难&#xff0c;难的是要用堆实现排序&#xff0c;也就是堆的运用。 下面需要探究一下堆的排序是怎样的。 如何利用堆进行升序或者降序的排序。 "堆排序"&#xff1a; 原理&#xff1a; 例如&#xff1a;此时要将数组里的数组int a…

干货实用帖 | PARASOFT与JENKINS 插件集成

&#x1f4d6; 介绍&#xff1a; 本篇介绍如何使用Jenkins上的插件Parasoft Findings&#xff0c;应用到C/Ctest项目中。 ✅ 准备工作&#xff1a; Jenkins项目C/Ctest 10.4以上版本及有效的许可证 视频教学&#xff1a; Parasoft与Jenkins插件集成 安装插件&#xff1a; 首先…

Vue3 获取农历(阴历)日期,并封装日历展示组件

前言&#xff1a;哈喽&#xff0c;大家好&#xff0c;我是码喽的自我修养&#xff01;今天给大家分享vue3项目中使用 chinese-lunar-calendar 插件获取农历(阴历)日期&#xff0c;并封装了日历展示组件&#xff01;提供了具体的代码帮助大家深入理解&#xff0c;彻底掌握&#…

【舞动生命,营养护航】亨廷顿舞蹈症患者的维生素补给站

Hey小伙伴们~&#x1f44b; 在这个充满色彩的世界里&#xff0c;每个人都在以自己的方式绽放光彩。但你知道吗&#xff1f;有一群特别的朋友&#xff0c;他们面对着亨廷顿舞蹈症的挑战&#xff0c;却依然以不屈不挠的精神舞动着生命的旋律。&#x1f483;✨ 今天&#xff0c;就…

游戏如何对抗 IL2cppDumper逆向分析

众所周知&#xff0c;Unity引擎中有两种脚本编译器&#xff0c;分别是 Mono 和 IL2CPP 。相较于Mono&#xff0c;IL2CPP 具备执行效率高、跨平台支持等优势&#xff0c;已被大多数游戏采用。 IL2CPP 模式下&#xff0c;可以将游戏 C# 代码转换为 C 代码&#xff0c;然后编译为…

STM32学习记录-06-ADC模数转换器

1 ADC简介 ADC(Analog-Digital Converter)模拟-数字转换器 ADC可以将引脚上连续变化的模拟电压转换为内存中存储的数字变量,建立模拟电路到数字电路的桥梁 12位逐次逼近型ADC,1us转换时间 输入电压范围:0~3.3V,转换结果范围:0~4095 18个输入通道,可测量16个外部和…

FPGA在医疗方面的应用

可编程逻辑支持以灵活、低风险的方式成功实施系统设计&#xff0c;同时提供了最佳的成本效率和增值的差异化功能&#xff0c;延长了医疗保健应用的生命周期&#xff0c;包括诊断成像、电子医疗、治疗和生命科学与医院设备。 在医疗方面的应用非常广泛&#xff0c;以下是几个主…

Langchain Memory组件深度剖析:从对话基础到高级链式应用

文章目录 前言一、Langchain memory 记忆1.Memory 组件基本介绍2.Memory 组件的类型1.ChatMessageHistory2.ConversationBufferMemory3.ConversationBufferWindowMemory4.ConversationEntityMemory5.ConversationKGMemory6.ConversationSummaryMemory 二、长时记忆1.简单介绍2.…

Error: Can not import paddle core while this file exists

背景 因为工作需要&#xff0c;原来的项目部署的电脑被征用&#xff0c;重新换了一个新电脑&#xff0c;重装了系统&#xff0c;今天在给一个使用ocr的项目进行环境配置的时候发现&#xff0c;无论安装哪个版本的paddlepaddle&#xff0c;总是可以安装成功&#xff0c;但是导入…

Android CCodec Codec2 (四)C2Param - Ⅱ

这一篇内容我们来解答复杂参数定义过程中提出的疑问&#xff0c;本文有大量的模板和宏展开&#xff0c;请耐心阅读。 1、不含灵活数组的复杂结构体定义 DEFINE_AND_DESCRIBE_C2STRUCT和C2FIELD是不能分开的&#xff0c;使用时必须要按顺序依次调用这两个宏定义。宏定义比较复杂…

【机器学习-监督学习】神经网络与多层感知机

【作者主页】Francek Chen 【专栏介绍】 ⌈ ⌈ ⌈Python机器学习 ⌋ ⌋ ⌋ 机器学习是一门人工智能的分支学科&#xff0c;通过算法和模型让计算机从数据中学习&#xff0c;进行模型训练和优化&#xff0c;做出预测、分类和决策支持。Python成为机器学习的首选语言&#xff0c;…

java-Mybaits框架01

1.框架概念 在基础语言之上&#xff0c;对各种基础功能进行封装&#xff0c;方便开发者&#xff0c;提高开发效率&#xff1b; java后端框架 mybaits&#xff1a;对jdbc进行封装 Spring&#xff1a;对整个java后端架构进行管理。 SpringWeb&#xff1a;对web&#xff08;S…

vxe-grid 利用dayjs提供的方法来格式化, 计算二个日期之间的年数/年龄

1、安装dayjs pnpm add dayjs yarn add dayjs npm install dayjs 2、导入 import dayjs from dayjs; 3、vxe-grid列&#xff1a; export const UserColumns: VxeGridPropTypes.Columns [ ... {title: 年龄,width: 70,field: old,showOverflow: tooltip,align: center,sortabl…

android studio 设置gradle jdk

1. 左上角点击file 2. 按照如下点击&#xff1a; 3. 即可修改gradle jdk