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

【文件】------操作文件

目录

一:文件的定义

二:文件名

三:文件类型

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* 的指针变量。

cs 复制代码
FILE* pf;    // 创建一个文件指针变量

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

4.2:文件的打开与关闭

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

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

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

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

打开文件:

关闭文件:

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

cs 复制代码
// 打开文件
FILE* fopen(const char* filename, const char* mode);

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

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

|--------------|----------------------|--------------|
| 文件使用打开方式 | 含义 | 若指定文件不存在 |
| " r "(只读) | 为了输入数据,打开一个已经存在的文本文件 | 出错 |
| "w"(只写) | 为了输出数据,打开一个文本文件 | 建立一个新的文件 |
| "a"(追加) | 向文本文件尾添加数据 | 出错 |
| "rb"(只读) | 为了输入数据,打开一个二进制文件 | 出错 |
| "wb"(只写) | 为了输出数据,打开一个二进制文件 | 建立一个新的文件 |

cs 复制代码
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");   // 写数据到二进制文件中

先看一个例子代码:

cs 复制代码
#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:读写字符

读字符:

写字符:

cs 复制代码
// 读函数使用形式:
int fgetc ( FILE * stream );

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



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

写数据到文件中:

cs 复制代码
#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;
}

程序运行前:

程序运行后:

读文件中的数据:

cs 复制代码
#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:读写字符串

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

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



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

写字符串数据

代码实例:

cs 复制代码
#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;
}

程序运行前:

程序运行后:

读字符串数据

代码实例:

cs 复制代码
#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:读写格式化数据

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


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

写格式化数据

代码实例:

cs 复制代码
#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;
}

程序运行结果前:

程序运行结果后:

读格式化数据

代码实例:

cs 复制代码
#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;
}

运行结果:

六:文件的随机读写

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

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

cs 复制代码
// 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

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

cs 复制代码
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编译系统决定的。

相关推荐
Cachel wood7 分钟前
python round四舍五入和decimal库精确四舍五入
java·linux·前端·数据库·vue.js·python·前端框架
Python之栈14 分钟前
【无标题】
数据库·python·mysql
风_流沙26 分钟前
java 对ElasticSearch数据库操作封装工具类(对你是否适用嘞)
java·数据库·elasticsearch
亽仒凣凣33 分钟前
Windows安装Redis图文教程
数据库·windows·redis
小林熬夜学编程40 分钟前
【Linux网络编程】第十四弹---构建功能丰富的HTTP服务器:从状态码处理到服务函数扩展
linux·运维·服务器·c语言·网络·c++·http
亦世凡华、42 分钟前
MySQL--》如何在MySQL中打造高效优化索引
数据库·经验分享·mysql·索引·性能分析
YashanDB44 分钟前
【YashanDB知识库】Mybatis-Plus调用YashanDB怎么设置分页
数据库·yashandb·崖山数据库
Jackey_Song_Odd1 小时前
C语言 单向链表反转问题
c语言·数据结构·算法·链表
ProtonBase1 小时前
如何从 0 到 1 ,打造全新一代分布式数据架构
java·网络·数据库·数据仓库·分布式·云原生·架构
A懿轩A2 小时前
C/C++ 数据结构与算法【数组】 数组详细解析【日常学习,考研必备】带图+详细代码
c语言·数据结构·c++·学习·考研·算法·数组