超详细的文件操作讲解

各位朋友们,大家好啊,今天我要分享的是关于文件操作方面的知识。

为什么会有文件操作

那么大家可能会问:为什么会有文件操作呢?前面我们可能都了解了通讯录,我们知道当我们使用通讯录的时候我们可以添加联系人,也可以删除联系人,但是当我们退出程序之后下次再进来的时候,我们要想看看通讯录里面有那些联系人,我们打开通讯录发现里面是空的,这是为什么呢?因为我们这种通讯录实在内存上操作的,当我们关闭程序或者关机的时候,这些内存就会被释放掉了,那么我们想要下次打开通讯录的时候,里面的内容还在的话,我们就需要使用文件来操作了。

什么是文件

文件通常是指磁盘上的文件,就像我们平时购买电脑的时候我们可能会买16+512的,这个16通常是指运行内存,我们写代码的时候通常使用的就是这个内存,而我们安装QQ、微信啊这些就是安装在磁盘上的,这些数据不会随着你电脑关机或者没电的时候而消失,他会一直存在,除非你故意删除或者磁盘损坏。所以我们使用文件来操作可以将数据存储在磁盘上保存。

文件又分为程序文件文件和内存文件。他们分类的依据是根据功能来分类的,不知道你们是否发现了,当我们写了一个代码并编译运行的时候,我们可以在我们项目的文件路径下发现.obj后缀和.exe后缀的文件,这些等等都属于程序文件,而当我们程序运行的时候读取的文件称为数据文件。

那么我们知道了什么是文件以及使用文件的好处了之后,我们来学习怎样进行文件操作。

文件操作

文件指针

每个被使用的文件都在内存中开辟了一个相应的文件信息区,用来存放文件的相关信息(如文件的名字,文件状态及文件当前的位置等)。这些信息是保存在一个结构体变量中的。该结构体类型是由系统声明的,取名FILE。也就是说我们需要使用FILE来找到文件的地址,并对其进行相关操作。其实这就跟普通指针差不多,就像int* p = &a,一样*说明他是一个指针变量,而int说明这个指针指向的是int类型的数据,FILE也是如此。

文件的打开与关闭

当我们使用文件的时候我们需要在知道使用的步骤,就像我们想要在冰箱里面拿东西一样,我们首先需要打开冰箱,然后我们可以从冰箱里面拿出东西也可以往冰箱里面放东西,我们进行文件操作的时候也是先打开文件,然后进行相关操作,最后就是关闭文件。

fopen(打开文件)

FILE * fopen ( const char * filename, const char * mode );

const char* filename是我们要打开的文件地址,const char* mode是我们以怎样的形式打开。

fclose(关闭文件)

int fclose ( FILE * stream );

FILE * stream是我们需要关闭的文件地址,这里我们需要注意的是fclose并不会将要关闭的文件置为NULL,所以我们需要手动置空。

接下来我们就来看看有哪些打开文件的方式吧。

打开文件的方式

在这里插入图片描述
我们在使用的时候可以根据需要以不同的方式打开。我们举个例子:
首先我们在我们的项目路径下创建一个test.txt文档,用来做测试。
在这里插入图片描述
然后我们在这个文档里面写入内容。
在这里插入图片描述

#include<stdio.h>

int main()
{
    
    
	//打开文件
	FILE* pf = fopen("test.txt", "r");
	if (pf == NULL)
	{
    
    
		perror("fopen");
	}
	
	//进行相关文件操作

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

	return 0;
}

在这里插入图片描述
我们这里就是以读的形式打开的。

文件的顺序读写

在这里插入图片描述
这里的流是什么意思呢?其实这个流只是一个抽象概念,就像一条河流,当我们需要灌溉农田的时候我们就可以用抽水机来抽取。我们的键盘和屏幕实际上也是一个文件,我们的电脑从键盘中读取数据,然后将数据显示到屏幕上,键盘也叫标准输入流(stdin),屏幕叫做标准输出流(stdout)。

那么我们来举几个例子来看看这写函数是什么作用吧。

fgets函数

char * fgets ( char * str, int num, FILE * stream );
#include<stdio.h>

int main()
{
    
    
	//打开文件
	FILE* pf = fopen("test.txt", "r");
	char arr[10] = {
    
     0 };
	if (pf == NULL)
	{
    
    
		perror("fopen");
		return 0;
	}
	
	//进行相关文件操作
	fgets(arr, 5, pf);
	printf("%s", arr);

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

	return 0;
}

在这里插入图片描述
虽然我们在这里想要读取5个元素,但是其实只读取了4个元素,因为最后一个元素要读取’\0’。

fputc函数

int fputs ( const char * str, FILE * stream );

我们先将前面的文档里面的内容删除。
在这里插入图片描述

#include<stdio.h>

int main()
{
    
    
	FILE* pf = fopen("test.txt", "w");
	if (pf == NULL)
	{
    
    
		perror("fopen");
		return 1;
	}
	//写文件
	//把26个字母写到文件中
	int i = 0;
	for (i = 0; i < 26; i++)
	{
    
    
		fputc('a'+i, pf);
	}

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

	return 0;
}

在这里插入图片描述

fgets函数

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

fgets可以读取一行的数据

#include<stdio.h>

int main()
{
    
    
	FILE* pf = fopen("test.txt", "r");
	if (pf == NULL)
	{
    
    
		perror("fopen");
		return 1;
	}
	//读
	char arr[20];
	fgets(arr, 5, pf);
	printf("%s\n", arr);

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

	return 0;
}

在这里插入图片描述

fputs函数

fputs写一行的数据

int fputs ( const char * str, FILE * stream );
#include<stdio.h>

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

	fputs("hello bit", pf);

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

	return 0;
}

在这里插入图片描述

fprintf函数

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

后面的省略号说明你自己可以定义长度。

#include<stdio.h>

struct S
{
    
    
	int n;
	float f;
	char arr[20];
};

int main()
{
    
    
	struct S s = {
    
     100, 3.14f, "zhangsan" };
	//打开文件
	FILE* pf = fopen("test.txt", "w");
	if (NULL == pf)
	{
    
    
		perror("fopen");
		return 1;
	}
	//写文件
	fprintf(pf, "%d %f %s\n", s.n, s.f, s.arr);

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

在这里插入图片描述

fscanf函数

int fscanf ( FILE * stream, const char * format, ... );
#include<stdio.h>

struct S
{
    
    
	int n;
	float f;
	char arr[20];
};

int main()
{
    
    
	struct S s = {
    
    0};
	//打开文件
	FILE* pf = fopen("test.txt", "r");
	if (NULL == pf)
	{
    
    
		perror("fopen");
		return 1;
	}
	//读文件
	fscanf(pf, "%d %f %s", &(s.n), &(s.f), s.arr);

	printf("%d %f %s\n", s.n, s.f, s.arr);

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

在这里插入图片描述
那么前面的都是顺序读写,但是当我们想要在任意位置写的时候我们又该怎么办呢?
我们这就得用到fseek函数和ftell函数了,这两个函数可以随机读写文件。

文件的非顺序读写

fseek函数

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

stram还是我们需要读取的文件的地址,offset 是相对于origin的偏移量,origin有三种不同的形式。SET表示文件的开始位置,CUR表示文件指针的当前位置,END表示文件的结尾。
在这里插入图片描述
在这里插入图片描述

#include<stdio.h>

int main()
{
    
    
	FILE* pf = fopen("test.txt", "r");
	if (pf == NULL)
	{
    
    
		perror("fopen file");
		return 1;
	}
	for (int i = 0; i < 5; i++)
	{
    
    
		fgetc(pf);
	}
	//现在pf文件指针已经向后移动了5个字节,现在我们想要读取的元素是b,b与文件首元素的地址的偏移量是1
	fseek(pf, 1, SEEK_SET);
	int a = fgetc(pf);
	printf("%c", a);

	fclose(pf);
	pf = NULL;

	return 0;
}

在这里插入图片描述

ftell函数

long int ftell ( FILE * stream );

ftell函数返回的是你当前的文件指针与文件开始的地址处的偏移量,这里我就不需要过多解释了。

rewind函数

void rewind ( FILE * stream );

这个函数的作用是让文件指针回到文件的起始位置

二进制读写

fwrite函数`

fwrite函数是针对二进制来说的,他写入的形式是以二进制来写的。

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

这个函数返回的是你写入的字符的个数,参数一个是ptr,代表的是从哪写入,一个是size,表明要写入的内容的大小,count是指要写入多少个这样的内容,stream是你要写入那个文件中。

#include<stdio.h>

struct S
{
    
    
	int n;
	float f;
	char arr[20];
};

int main()
{
    
    
	struct S s = {
    
     10,3.14f,"hello" };
	FILE* pf = fopen("test.txt", "wb");
	if (pf == NULL)
	{
    
    
		perror("fopen");
		return 1;
	}
	fwrite(&s, sizeof(struct S), 1, pf);

	fclose(pf);
	pf = NULL;

	return 0;
}

在这里插入图片描述
这样我们可能看不懂吧,因为这是以二进制的形式写入的,所以我们并不能看懂。

fread函数

size_t fread ( void * ptr, size_t size, size_t count, FILE * stream );
#include <stdio.h>
struct S
{
    
    
	char name[20];
	int age;
	float score;
};

int main()
{
    
    
	struct S s = {
    
    0};
	FILE* pf = fopen("test.txt", "rb");
	if (pf == NULL)
	{
    
    
		perror("fopen");
		return 1;
	}
	//读文件
	fread(&s, sizeof(struct S), 1, pf);
	printf("%s %d %f\n", s.name, s.age, s.score);

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

	return 0;
}

在这里插入图片描述

结语

那么这些就是我学到的关于文件操作的只是,感谢大家的观看,如有错误,请随时订正。

猜你喜欢

转载自blog.csdn.net/m0_73888323/article/details/129826267