文件的操作

本文详细介绍了文件在编程中的作用,包括数据持久化、不同类型文件(磁盘文件、程序文件和数据文件)及其在程序中的角色。文章还讲解了流的概念,如标准流、文件流,以及文件的打开、关闭、读取(如fgetc、fputc、fgets和printf)和写入(如fputc、fputs、fprintf)方法。此外,还涉及随机读取的控制函数如fseek、ftell和rewind。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一、文件作用:

·        将数据进行持久化的保存;防止数据因为程序退出,内存的回收而丢失

二、文件分类:

1、磁盘文件:

        顾名思义硬盘或者磁盘上的文件

2、在程序上:

1)、程序文件:

(我们写程序时,写下的文件以及编译链接的文件)

源文件: 后缀为 .c 文件

目标文件:后缀为 .obj 文件(Windows环境下)     .o文件(Linux环境)

可执行文件:后缀为 .exe文件

2)、数据文件:

(程序运行时读写的数据)

1->文本文件:

内存中以二进制的形式存储,要求在外存以ASCII字符的形式存储的文件

      👉字符数 取决于✨数值位数 (这里不考虑大小端字节序)就是说3位数 就是占用 3字节

0011这个是固定的 理解前缀,因为我们将多位数以ASCII码值存储,但是ASCII码值有限的,所以将多位数拆分成 个位数存储 ,这样就不会出现存不下的情况

2->二进制文件:

二进制的形式存储,不加以转化   直接存储到外存的 文件

 👉✨字符数(字节数)不取决于数值位数(不考虑大小端字节序)也就是64位环境下int 占4个字节

注意:

        后面空的部分是不要的!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!😅画多了

 三、流的引入:

        为了方便程序员对各种设备进行操作,引入了流这一概念,我们可以将流想象成一条流淌着字符的  河流

介绍一个类型: FILE*  —— 文件指针

1、标准流:

        1、标准输入流:stdin

                读取普通输入的流,大多环境是键盘输入,scanf与getchar等函数会在这个流读取                                                                                 字符!

        2、标准输出流:stdout

                写入普通输出的流,大多环境是输出至显示器界面,printf、putchar、puts等函数                                                                      会向这个流写入字符

        3、标准错误流:stderr

                用于写出错误的流,大多环境是输出至显示器界面。

🧑‍🎓很好记就是stdio的头文件不要io 后面接 in out err🧑‍🎓

2、文件流:

        我们创建的文件就是文件流;可以通过不同函数进行操作,向文件进行读取或者写入,根据不同模式下 文件的角色也是不同的,可以当输出流,可以当输入流

总之就是文本既可以是输入流也可以是输出流

四、文件操作:

1、文件的打开和关闭:

✨可以想象一下,我们喝水的时候👉顺序是怎么样的呢??

打开水瓶——>检查水是否能喝,是否是饮用水——>喝水(装水)——>拧上盖子

文件的打开也是如出一辙

(1)、打开文件:

fopen就是打开文件   传的本质其实是字符串

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

 

 以写的形式打开:

创建一个文件指针接收这个文件!!

(2)、检查是否正确:

✨进行检查,竟然是指针类型的函数,那么发生错误则就是返回空指针(NULL)

若是为空,return 1;表示🐸提前返回的意思!

perror检查是否发生错误,若是错误则会打印在屏幕上

(3)、关闭文件

fclose用来关闭文件

int fclose(FILE* stream);

 关闭了文件,防止我们创建的文件指针变成野指针,要把他变成空指针!!

 

✨✨对于指针一定要记住不让 野狗 发疯

2、读取以及写入的模式介绍:

下面就是关于文件的打开方式:看表格即可

3、文件顺序读写:

读:将文本看成输入流(相当于键盘),从中读取!

写:将文本看成输出流(相当于屏幕),写入里面!


A、字符输入函数 fgetc():  向文件读取

 将文本看成输入流,从中读取字符,返回字符的ASCII码值!可以用int 型去接收

看下画红线部分,进去时有一个光标,你读取一个字符光标会右移,直到读完,,下面用的函数也是如此,不在赘述

✨该函数读取:

——>成功返回读取的字符

——>到达末尾时就会返回EOF

——>失败也是返回EOF,并且会标记这个错误;(perror可以检查)

注意:以下为例子注意,读取方式r 的含义,要文件存在才行!!!!!!

int main()
{

	//从文件读取;
	FILE* pf2 = fopen("test.txt", "r");
	int ch = 0;
	while ((ch = fgetc(pf2))!=EOF)
	{
		printf("%c ", ch);
	}
	fclose(pf2);
	pf2 == NULL;
return 0;
}

B、字符输出函数fputc(): 向文件写入 

✨文件可以看出输出流, 传你需要传的字符,写入到指定的文件里面去;

该函数:

——>成功返回写入的字符

——>失败返回EOF,并且会标记这个错误;(perror可以检查)

实现:

int main()
{
	FILE* pf1 = fopen("test.txt", "w");
	if (pf1 == NULL)
	{
		perror("fopen");
		return 1;
	}
	//写文件;写入;
	char c = 0;
	for (c = 'a'; c <= 'z'; c++)
	{
		fputc(c, pf1);
	}
	fclose(pf1);
	pf1 == NULL;
	return 0
}

C、文本行输入函数fgets():向文件读取

文本可以看成流

注:        一行一行进行读取,将读取到的放到空间里面,因为是ASCII码值的形式存入,所以一个字节一个字符;然后最后一个后间会给\0,相当于到第19个字符时会补\0,若是所在行读取字符不够了\n也会读取掉然后再补\0

该函数:

失败——>返回NULL

到达文件末尾——>返回NULL

实现一下:

我用while循环进行

int main()
{
	//以读的形式打开文件
	FILE *pf = fopen("test.txt", "r");
	if (pf == NULL)
	{
		perror("fopen");
		//提前返回!
		return 1;
	}
	//读取文件一行的字符
	char arr[20] = { 0 };
	//到19个字符会自动补\0;
	while ((fgets(arr, 20, pf)) != NULL)
	{
		printf("%s", arr);
	}

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

	return 0;
}

D、文本行输出函数fputs():向文件输入

 将想要写入的数据写入文本中,根据光标走,不会自动换行,需要自己带\n;

一直写入,碰到\0就停止写入

注意:不会将\0写入到里面!!

实现:

int main()
{
	//以写入的模式打开文件
	FILE* pf = fopen("test.txt", "w");
	if (pf == NULL)
	{
		perror("fopen");
		return 1;
	}
	char arr[20] = { "hellow word\n" };
	//以文本行输出(写入),要换行就需要写 \n !!!!
	fputs(arr, pf);

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

E、格式化输入fscanf():写法与scanf相同,多了一个流

有点抽象,但是看例子很容易理解 

 这个写法一般用结构体来读取文本;并非只用来写结构体

若没有执行任何转换则是发生输入错误,返回EOF(-1);

若成功了返回成功输入的项数

若发生错误返回比输入的项数少的实参个数,甚至是0:

实现:

int main()
{
	struct st s = { 0 };
	//以读取模式打开文件
	FILE* pf = fopen("test.txt", "r");
	if (pf == NULL)
	{
		perror("fopen");
		return 1;
	}
	fscanf(pf, "%s%d%lf",s.name,&(s.ege),&(s.hight));

	printf("%s %d %f", s.name, s.ege, s.hight);
	//关闭
	fclose(pf);
	pf = NULL;

	return 0;
}

F、格式化输出函数fprintf():写法与printf相同,多了一个流

写入,和上E的填写内容差不多

 将内容写入到文件里面

成功——>返回发送的字符个数

发生错误——>返回负值

struct st {
	char name[128];
	int ege;
	double hight;
};
//int fprintf(FILE* stream,const char* format,……);
int main()
{
	struct st s = { "zhangsan",22,1.78 };
	FILE* pf = fopen("test.txt", "w");
	if (pf == NULL)
	{
		perror("fopen");
		return 1;
	}
	//fprintf写入(文本形式写入)
	fprintf(pf, "%s %d %.1f",s.name,s.ege,s.hight);

	fclose(pf);
	pf = NULL;
	

	return 0;
}

总结下:

        其实上面ABCDEF也适用于标准流使用,将文件指针的位置,写入标准流一样能达到效果,就像:fscanf 给他里面加入 stdin 与scanf的效果是一样的

G、二进制输入fread():

返回成功读取的元素个数

当发生错误或者读到文件末尾时,元素个数会少于nmemb个

实现如下:

int main()
{
	int arr[10] = {0};
	//打开文件
	FILE* pf = fopen("sred.txt", "rb");
	if (pf == NULL)
	{
		perror("fopen");
		return 1;
	}
	//读取
	int cont = fread(arr, sizeof(arr[0]), 6, pf);
	for (int i = 0; i < cont; i++)
	{
		printf("%d ", arr[i]);
	}
	//关闭文件
	fclose(pf);
	pf = 0;
	return 0;
}

H、二进制输出fwrite():

返回写入成功的个数

若发生错误或者到达文件末尾 返回的个数少于nmemb 

实现:

int main()
{
	int arr[10] = { 1,2,3,4,5,6 };
	//打开文件
	FILE* pf = fopen("sred.txt", "wb");
	if (pf == NULL)
	{
		perror("fopen");
		return 1;
	}
	int sz = sizeof(arr) / sizeof(arr[0]);
	//写入
	fwrite(arr, sizeof(arr[0]), sz, pf);

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

对上述总结:看下表

4、随机读取:

1》根据文件指标位置和偏移量来定位文件指针 fseek():

 有如下三种选择:

int main()
{
	FILE* pf1 = fopen("test.txt", "w");
	if (pf1 == NULL)
	{
		perror("fopen");
		return 1;
	}
	//写文件;写入;
	char c = 0;
	for(c = 'a'; c <= 'z'; c++)
	{
		fputc(c, pf1);
	}
	fclose(pf1);
	pf1 == NULL;
	//从文件读取;打开文件
	FILE* pf2 = fopen("test.txt", "r");
	int ch = 0;
	while ((ch = fgetc(pf2))!=EOF)
	{
		printf("%c ", ch);
	}
	fseek(pf2, 3, SEEK_SET);
	putchar('\n');
	while ((ch = fgetc(pf2)) != EOF)
	{
		printf("%c ", ch);
	}
	fclose(pf2);
	pf2 == NULL;
	return 0;
}

 起始位置在a的前面为初始位置

 2》返回文件指针相当于起始位置的偏移量ftell():

 实现如下:

int main()
{
	FILE* pf1 = fopen("test.txt", "w");
	if (pf1 == NULL)
	{
		perror("fopen");
		return 1;
	}
	//写文件;写入;
	char c = 0;
	for(c = 'a'; c <= 'z'; c++)
	{
		fputc(c, pf1);
	}
	fclose(pf1);
	pf1 == NULL;
	//从文件读取;打开文件
	FILE* pf2 = fopen("test.txt", "r");
	int ch = 0;
	while ((ch = fgetc(pf2))!=EOF)
	{
		printf("%c ", ch);
	}
	fseek(pf2, 3, SEEK_SET);
	putchar('\n');
	while ((ch = fgetc(pf2)) != EOF)
	{
		printf("%c ", ch);
	}
	putchar('\n');
	long int s = ftell(pf2);
	printf("%d", s);
	fclose(pf2);
	pf2 == NULL;
	return 0;
}

3》让文件指针的位置回到文件起始位置rewiind():

 

int main()
{
	FILE* pf1 = fopen("test.txt", "w");
	if (pf1 == NULL)
	{
		perror("fopen");
		return 1;
	}
	//写文件;写入;
	char c = 0;
	for(c = 'a'; c <= 'z'; c++)
	{
		fputc(c, pf1);
	}
	fclose(pf1);
	pf1 == NULL;
	//从文件读取;打开文件
	FILE* pf2 = fopen("test.txt", "r");
	int ch = 0;
	while ((ch = fgetc(pf2))!=EOF)
	{
		printf("%c ", ch);
	}
	fseek(pf2, 3, SEEK_SET);
	putchar('\n');
	while ((ch = fgetc(pf2)) != EOF)
	{
		printf("%c ", ch);
	}
	putchar('\n');
	long int s = ftell(pf2);
	printf("%d", s);
	//光标会到初始位置
	rewind(pf2);
	putchar('\n');
	s = ftell(pf2);
	printf("%d", s);
	pf2 == NULL;
	return 0;
}

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值