【C语言】文件操作

谢谢观看!希望以下内容帮助到了你,对你起到作用的话,可以一键三连加关注!你们的支持是我更新地动力。
因作者水平有限,有错误还请指出,多多包涵,谢谢!


一、为什么使用文件?

  如果没有文件,我们写的程序的数据是存储在电脑的内存中,如果程序退出,内存回收,数据就丢失了,等再次运行程序,是看不到上次程序的数据的,如果要将数据进行持久化的保存,我们可以使用文件。
  


二、什么是文件?

  磁盘(硬盘)上的文件是文件。但是在程序设计中,我们一般谈的文件有两种:程序文件数据文件(从文件功能的角度来分类的)

2.1程序文件

  程序文件包括源程序文件(后缀为.c),目标文件(windows环境后缀为.obj),可执行程序(windows环境后缀为.exe)。

2.2数据文件

  文件的内容不一定是程序,而是程序运行时读写的数据,比如程序运行需要从中读取数据的文件,或者输出内容的文件
  本章讨论的是数据文件
  在以前各章所处理数据的输入输出都是以终端为对象的,即从终端的键盘输入数据,运行结果显示到显示器上。
  其实有时候我们会把信息输出到磁盘上,当需要的时候再从磁盘上把数据读取到内存中使用,这里处理的就是磁盘上文件
在这里插入图片描述

2.3文件名

在这里插入图片描述


三、二进制文件和文本文件?

  从文件内存储数据的形式来看,数据文件分为2种类型

  • 二进制文件:数据在内存中以二进制的形式存储,如果不加转换的输出到外存的文件中,就是二进制文件
  • 文本文件 :如果要求在外存上以ASCII码的形式存储,则需要在存储前转换,以ASCII字符的形式存储的文件就是文本文件

  在了解了二进制文件文本文件的区别后,那么一个数据在文件中是怎么存储的呢

  字符一律以ASCII形式存储,数值型数据既可以用ASCII形式存储也可以使用二进制形式存储。举个例子:

#include <stdio.h>
int main()
{
 int a = 10000;
 FILE* pf = fopen("test.txt", "wb");//wb是二进制写的方式来打开文件 表示 将数据以二进制的形式写入文件中保存起来
 fwrite(&a, 4, 1, pf);//⼆进制的形式写到⽂件中
 //&a表示将a数据写入文件;4表示写入4个字节;1表示写入1次;pf表示写到pf所指向的文件里面去
 fclose(pf);//关闭pf指针指向的文件
 pf = NULL;//防止pf为野指针,置为空指针
 return 0;
}

四、文件的打开和关闭

4.1流和标准流

4.1.1流

在这里插入图片描述
在这里插入图片描述

4.1.2标准流

在这里插入图片描述

4.2文件指针

4.3 文件的打开和关闭

  文件在读写之前应该先打开文件,在使用结束之后应该关闭文件
  
  在编写程序的时候,在打开文件的同时,都会返回⼀个FILE*的指针变量指向该文件,也相当于建立了指针和文件的关系
  
  ANSIC 规定使用 fopen 函数来打开文件, fclose 来关闭文件。

//打开⽂件
FILE * fopen ( const char * filename, const char * mode );
//const char * filename表示文件名
//const char * mode表示文件打开方式

//关闭⽂件
int fclose ( FILE * stream );

  在上面的代码中,mode表示文件打开的方式,而文件打开的方式有很多种类,由于挺多的,我将它们放入到一个图片中去了。文件打开方式的种类 图片展示
  实例代码:

#include <stdio.h>
int main ()
{
	//1.打开⽂件
	//打开文件成功的话,返回的是有效的指针
	//如果打开失败,则返回NULL
 	FILE * pFile = fopen ("myfile.txt","w");
 	//检测文件是否打开成功
 	if (pf == NULL)
 	{
		perror("fopen");//打印出 文件打开失败的原因
		return 1;
	}

 	//写文件 - ⽂件操作
 	if (pFile!=NULL)
 	{
 		fputs ("fopen example",pFile);
  	}

	//关闭⽂件
 	fclose (pFile);
	pFile = NULL;//和free()函数的用法一样
 return 0;
}

  补充知识:在打开文件时的文件名可以写成绝对路径相对路径,看下面的代码:

int main()
{
	//1. 打开文件
	//打开文件成功的话,返回的是有效的指针
	//如果打开失败,则返回NULL
	FILE* pf = fopen("C:\\Users\\Administrator\\Desktop\\test.txt", "w");//绝对路径的写法
	//注意:在使用"w"打开文件时,如果文件存在,则会清空文件中的内容
	FILE* pf = fopen(".\\..\\..\\test.txt", "w");//相对路径的写法
	//. 表示当前路径
	//.. 表示上一级路径

	if (pf == NULL)
	{
		perror("fopen");
		return 1;
	}
	//写文件


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

	return 0;
}

五、文件的顺序读写

5.1顺序读写函数介绍

在这里插入图片描述

int  ch = fgetc(stdin);//stdin表示标准输入流
//从键盘(标准输入流)上读取字符
fputc(ch,stdout)//将读取到的字符输出(写)到屏幕上(标准输出流)

总结:所有输入输出流,包括了文件输入输出流、标准输入输出流、其他输入输出流

1.fputc函数
int fputc ( int character, FILE * stream );
fputc('a',pf);

2.fgetc函数
int fgetc(FILE * stream);
//读取正常的时候,返回读取到的字符的ASCII码值;读取失败的时候,返回EOF
//EOF  -- end of flie ---  文件的结束标志  ---  本质是-1
int ch = 0;
while((ch = fgetc(pf)) != EOF)
{
	printf("%c ",ch);
}

3.fgets函数
char * fgets(char * str,int num,FILE * stream);
//num表示str最多可以从一串字符串中拷贝的个数,包括\0,所以会从数据文件中拷贝num-1个数据+\0字符(字符串结束标志)
//注意:当数据文件中有多行字符串时,num>第一行字符串个数,str拷贝至\n + \0就会停止拷贝
//str拷贝读取到的字符串
char arr[20]= "xxxxxxxxxxxx";
fgets(arr,10,pf);
printf("%s\n",arr);

4.fputs函数
int fputs ( const char * str, FILE * stream );
//str接收字符串首字符的地址   
fputs("I am lihua",pf);

5.fscanf格式化输入函数(读文件,输入数据)
//
 struct S
{
	char name[20];
	int age;
	float score;
};


int main()
{
	
	struct S s = {0};
	//打开文件
	FILE* pf = fopen("test.txt", "r");

	if (pf == NULL)
	{
		perror("fopen");
		return 1;
	}
	
//从文件中读取信息,存放到s的各个成员中
	fscanf(pf, "%s %d %f", s.name, &(s.age), &(s.score));
	//scanf"%s %d %f", s.name, &(s.age), &(s.score));
	
//打印到屏幕上
printf("%s %d %f",s.name,s.age,s.score);
fprintf(stdout,"%s %d %f",s.name,s.age,s.score);

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

	return 0;
}

6.fprintf格式化输出函数(写文件,输出数据) 
int fprintf(FILE * stream ,const char * format,...)

char name[20] = "zhangsan";
int age = 20;
float score = 95.5f;
FILE * pf = fopen("test.txt","w");
if(pf == NULL)
{
	perror("fopen");
	return 1;
}
fprintf(pf,"%s %d %f",name,age,score);
printf("%s %d %f",name,age,score);
fclose(pf);
pf=NULL;



7.fread(二进制的输入)
size_t fread ( const void * ptr, size_t size, size_t count, FILE * stream );
struct S
{
	char name[20];
	int age;
	float score;
};

int main()
{
	struct S s = {0};
	//读取二进制的信息到文件中

	//1.打开文件
	FILE* pf = fopen("test.txt", "rb");
	if (pf == NULL)
	{
		perror("fopen");
		return 1;
	}
	//2.写文件
	fread(&s, sizeof(struct S), 1, pf);

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

	return 0;
}


8.fwrite(二进制的输出)
size_t fwrite ( const void * ptr, size_t size, size_t count, FILE * stream );
//ptr指向一个数组或者是一个字符串
//size表示一个元素的大小(字节数)
//count表示元素个数
//stream表示流

struct S
{
	char name[20];
	int age;
	float score;
};

int main()
{
	struct S s = { "cuihua",25,88.8f };
	//以二进制的形式写到s中

	//1.打开文件
	FILE* pf = fopen("test.txt", "wb");
	if (pf == NULL)
	{
		perror("fopen");
		return 1;
	}
	//2.读文件
	fwrite(&s, sizeof(struct S), 1, pf);
	
	printf("%s %d %f\n",s.name,s.age,s.score);
	//3.关闭文件
	fclose(pf);
	pf = NULL;

	return 0;
}

5.2对比一组函数

scanf/printf  针对标准输入流/标准输出流的  格式化  输入/输出函数

fscanf/fprintf 针对所有输入流/所有输出流的 格式化 输入/输出函数

sscanf/sprintf 将格式化的数据转换成字符串,或者是从字符串中提取格式化的数据

//sprintf其实是将格式化的数据写到字符串中,可以理解为:将格式化的数据转换成字符串
//sscanf    是从字符串中提取格式化的数据,可以理解为:将字符串转成格式化的数据
//例子
struct S
{
	char name[20];
	int age;
	float score;
};
int main()
{
	char arr[100] = { 0 };
	struct S s = { "wangwu",23,66.6f };
	
	//临时变量
	struct S tmp = {0};
	
	//将s中的各个数据转换成字符串,存放在arr中
	sprintf(arr, "%s %d %f", s.name, s.age, s.score);
	printf("%s\n", arr);//以字符串的形式打印出来的数据
	
	//从字符串arr中提取格式化的数据,存放在tmp中
	sscanf(arr,"%s %d %f",tmp.name,&(tmp.age),&(tmp.score));
	printf("%s %d %f", tmp.name, tmp.age, tmp.score);
	
	return 0;
}

六、文件的随机读写

6.1 fseek

根据文件件指针的位置和偏移量来定位文件指针(文件内容的光标)。

int fseek ( FILE * stream, long int offset, int origin );
//offset表示偏移量
//origin表示起始位置
int main()
{
	//1. 打开文件
	FILE* pf = fopen("test.txt", "r");
	if (pf == NULL)
	{
		perror("fopen");
		return 1;
	}
	//2.读文件
	int ch = 0;
	ch = fgetc(pf);//a
	printf("%c\n", ch);
	ch = fgetc(pf);//b
	printf("%c\n", ch);

	//定位文件指针
	//fseek(pf, 4,SEEK_SET);//文件的起始位置
	//fseek(pf, 2, SEEK_CUR);//文件的当前位置
	fseek(pf, -2, SEEK_END);//文件的末尾
	ch = fgetc(pf);//e
	printf("%c\n", ch);

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

	return 0;
}

6.2 ftell

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

long int ftell ( FILE * stream );
int main()
{
	//1. 打开文件
	FILE* pf = fopen("test.txt", "r");
	if (pf == NULL)
	{
		perror("fopen");
		return 1;
	}
	//2.读文件
	int ch = 0;
	ch = fgetc(pf);//a
	printf("%c\n", ch);
	ch = fgetc(pf);//b
	printf("%c\n", ch);

	//定位文件指针
	fseek(pf, -2, SEEK_END);
	ch = fgetc(pf);//e
	printf("%c\n", ch);

	//输出文件指针相较于文件的起始位置的偏移量
	printf("%d\n", ftell(pf));//5

	//将文件指针重新定位到文件的起始位置
	rewind(pf);
	ch = fgetc(pf);//a
	printf("%c\n", ch);

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

	return 0;
}

6.3rewind

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

 void rewind ( FILE * stream );
int main()
{
	//1. 打开文件
	FILE* pf = fopen("test.txt", "r");
	if (pf == NULL)
	{
		perror("fopen");
		return 1;
	}
	//2.读文件
	int ch = 0;
	ch = fgetc(pf);//a
	printf("%c\n", ch);
	ch = fgetc(pf);//b
	printf("%c\n", ch);

	//定位文件指针
	fseek(pf, -2, SEEK_END);
	ch = fgetc(pf);//e
	printf("%c\n", ch);

	//输出文件指针相较于文件的起始位置的偏移量
	printf("%d\n", ftell(pf));//5

	//将文件指针重新定位到文件的起始位置
	rewind(pf);
	ch = fgetc(pf);//a
	printf("%c\n", ch);

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

	return 0;
}

七、文件读取结束的判定

7.1 被错误使用的 feof

在这里插入图片描述
在这里插入图片描述

#include <stdio.h>
#include <stdlib.h>
int main(void)
{
 int c; // 注意:int,⾮char,要求处理EOF
 FILE* fp = fopen("test.txt", "r");
 if(!fp) {
 perror("File opening failed");
 return EXIT_FAILURE;
 }
 //fgetc 当读取失败的时候或者遇到⽂件结束的时候,都会返回EOF
 while ((c = fgetc(fp)) != EOF) // 标准C I/O读取⽂件循环
 { 
 putchar(c);
 }
 //判断是什么原因结束的
 if (ferror(fp))//检测到因其他原因失败,返回非0值
 puts("I/O error when reading");
 else if (feof(fp))//检测到因遇到文件末尾,返回非0值
 puts("End of file reached successfully");
 fclose(fp);
}

八、文件缓冲区

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值