资讯专栏INFORMATION COLUMN

C语言文件操作0基础保姆级教程

lixiang / 600人阅读

摘要:二文件操作基础知识什么是文件我们一般谈的文件有两种程序文件数据文件程序文件包括源程序文件后缀为目标文件环境后缀为可执行程序环境后缀为。也就是说,通过文件指针变量能够找到与它关联的文件。同时自行输入的字符串起到标识的作用,不会混淆。

目录

一、前言

二、文件操作基础知识

①什么是文件

②数据文件类型

③数据如何存储

④如何读取二进制文件

⑤什么是文件名

⑥文件缓冲区

⑦文件指针

三、文件操作函数

①fopen 与 fclose

②fputc与fgetc

③fputs与fgets

④fprintf与fscanf

⑤fwrite与fread

⑥fseek与ftell与rewind

⑦ferror与feof

⑧补充函数 sscanf sprintf  

⑨补充函数perror  strerror


一、前言

        我们如何使我们设计的程序具有“记忆功能”呢?答案是将数据以文件的形式另外保存。保存的形式有很多,在本文中我们以最简单的文本形式保存在记事本上,相信这篇文章一定让你学会。

二、文件操作基础知识

①什么是文件

我们一般谈的文件有两种:程序文件数据文件
<程序文件>
包括源程序文件(后缀为.c),目标文件(windows环境后缀为.obj),可执行程序(windows环境后缀为.exe)。
<数据文件>
文件的内容不一定是程序,而是程序运行时读写的数据,比如程序运行需要从中读取数据的文件,或者输出内容的文件。

本章讨论的是数据文件

②数据文件类型

文本文件与二进制文件

数据在内存中以二进制的形式存储,如果不加转换的输出到外存,就是<二进制文件>(后缀.bin)。

如果要求在外存上以ASCII码的形式存储,则需要在存储前转换。以ASCII字符的形式存储的文件就是<文本文件>(后缀.txt)。

③数据如何存储

一个数据在内存中是怎么存储的呢?
字符一律以ASCII形式存储,数值型数据既可以用ASCII形式存储,也可以使用二进制形式存储。
如有整数10000,如果以ASCII码的形式输出到磁盘,则磁盘中占用5个字节(按照一个字符一个字符储存,1  0  0  0  0每个字符一个字节),而二进制形式输出,则在磁盘上只占4个字节(int)

④如何读取二进制文件

文本文件是我们通过记事本可以直接理解读取的,而二进制文件如果以记事本的形式打开是我们不能识别的乱码。但vs可以以某种方式读取二进制文件,方法如下:

(下图表示以记事本读取以二进制形式保存的10000) 

 演示二进制文件打开方式: 

 第一步:将文件添加到vs下

 第二步:右击后打开方式选择二进制编译器

 

 这就是最后的效果了。

⑤什么是文件名

文件名包含3部分:文件路径+文件名主干+文件后缀
例如: c: /code/ test.txt  (在后文会提到对文件名的绝对引用和相对引用)

 ⑥文件缓冲区

含义:ANSIC 标准采用“缓冲文件系统”处理的数据文件。所谓缓冲文件系统是指系统自动地在内存中为程序中每一个正在使用的文件开辟一块“文件缓冲区”。文件缓冲区是用以暂时存放读写期间的文件数据而在内存区预留的一定空间。通过磁盘缓存来实现,磁盘缓存本身并不是一种实际存在的存储介质,它依托于固定磁盘,提供对主存储器存储空间的扩充,即利用主存中的存储空间, 来暂存从磁盘中读出(或写入)的信息。。

特点:从内存向磁盘输出数据会先送到内存中的缓冲区,装满缓冲区后才一起送到磁盘上。如果从磁盘向计算机读入数据,则从磁盘文件中读取数据输入到内存缓冲区(充满缓冲区),然后再从缓冲区逐个地将数据送到程序数据区(程序变量等)。缓冲区的大小根据C编译系统决定的 。

[扩展-三种类型的缓存区]           链接-文件缓冲区

⑦文件指针

<文件指针>

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

每当打开一个文件的时候,系统会根据文件的情况自动创建一个FILE结构的变量,并填充其中的信息,使用者不必关心细节。一般都是通过一个FILE的指针来维护这个FILE结构的变量,这样使用起来更加方便。

FILE*p//文件类型指针

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

三、文件操作函数

①fopen 与 fclose

1.fopen

<功能>打开文件

<参数>  filename-文件名         mode-打开方式        

<返回值>一个文件指针

(打开方式mode表)

 2.fclose

<功能>  关闭文件

<参数>  stream-文件指针 

3.使用示范

#include#include#includeint main(){	FILE*pw = fopen("test.txt","w");//打开的文件为“test.txt”      打开方式为“w”    if(pw==NULL)//若打开失败则说明失败原因并结束进程    {        printf("%s",strerror(errno));//errno是全局错误变量  strerror将errno解析为错误原因        return 0;    }	fclose(pw);//关闭文件	pw = NULL;//将指针置为空,防止被误用	return 0;}

 文件名相对/绝对路径

绝对路径:如c:/code/test.txt     包含文件路径  文件主干  文件后缀

相对路径:上图的表示就是相对路径,表示txt文件与源文件在同一路径下,若要表示上一路                    劲,则用“../”,一次类推上上路径就是“../../

FILE*pw = fopen("../test.txt","w");

②fputc与fgetc

1.fputc——输出函数

<功能>将一个字符写入流中

<参数>c-输出的字符

<返回值>正常——返回输出的字符

               错误——返回EOF

<适用>所有流

2.fgetc——输入函数

<功能>从流中读取一个字符

<返回值>int——返回输入的字符

               EOF——发生错误或到达文件结尾

<适用>所有流 

 3.使用示范

#include #include #include//fputc   输出一个字母int main(){	FILE*pw = fopen("test.txt","w");	if (pw == NULL)	{		printf("%s",strerror(errno));		return 0;	}	fputc("b",pw);//将字符‘b’写入文件"test.txt"	fclose(pw);	pw = NULL;	return 0;}//fgetc 读取一个字符,读取一个后文件指针往后偏移一位int main(){	FILE*pr = fopen("test.txt","r");	if (pr == NULL)	{		printf("%s",strerror(errno));		return 0;	}	char ch = 0;//用ch接收输入的字符	ch = fgetc(pr);//从文件"test.txt"中读取,读取一个字符后文件指针自动往后移一位	fclose(pr);	pr = NULL;	printf("%c",ch);	return 0;}

 4.对所有流的理解

什么是流:流是指信息从外部输入设备(如键盘)向计算机内部(如内存)输入和从内存                        向外部输出设备(显示器)输出的过程。                       

上述代码演示的是对文件流的操作,我们在用标准输入(stdin)输出(stdout)流演示一下

③fputs与fgets

1.fputs——输出函数

<功能>将字符串写入流中

<返回值>int——非负值表示成功

               EOF——发生错误

<适用>所有流

2.fgets——输入函数

<功能>从流中获取字符串

<返回值>正常——返回字符串

               NULL——表示错误或者到达文件结尾

<参数>n-从流中读取的最大字符数(/0会自动占去一位)

3.使用示范

#include #include #include//fputsint main(){	FILE*pw = fopen("test.txt","w");	if (pw == NULL)	{		printf("%s",strerror(errno));		return 0;	}	char ch[5] = "abcd";	fputs(ch,pw);	fclose(pw);	pw = NULL;	return 0;}//fgetsint main(){	FILE*pr = fopen("test.txt","r");	if (pr == NULL)	{		printf("%s",strerror(errno));		return 0;	}	char ch[5] = {0};	fgets(ch,3,pr);//有一位自动被/0占用	printf("%s",ch);	return 0;}

④fprintf与fscanf

1.fprintf——输出函数

<功能>将特定格式的数据写入流中

<返回值>返回打印的字节数。

<适用>所有流

<对比>printf默认将数据打印在标准输出流(stdout)上,而fprintf的输出流可以选择。printf             打印的字符数返回

 2.fscanf——输入函数

<功能>从流中读取特定格式的数据

<适用>所有流

<返回值>返回成功转换和分配的字段数量

3.使用示范

//头文件同上略//fprintfint main(){	FILE*pw = fopen("test.txt","w");	if (pw == NULL)	{		printf("%s",strerror(errno));		return 0;	}	fprintf(pw,"%d %.2f %c",10,3.14,"a");	fclose(pw);	pw = NULL;	return 0;}//fscanfint main(){	int a; float b; char c;	FILE*pr = fopen("test.txt","r");	if (pr == NULL)	{		printf("%s",strerror(errno));		return 0;	}	fscanf(pr,"%d %f %c",&a,&b,&c);	printf("%d %.2f %c", a,b,c);	return 0;}

⑤fwrite与fread

1.fwrite——输出函数

<功能>将数据以二进制的形式写入文件流中

<参数>buffer-指向写入数据的指针    size-每一个元素的大小   count-写入的最大元素数

<返回值>实际写入的元素数

<适用>文件流

2.fread——输入函数

<功能>将数据以二进制的形式从文件流中读取

<返回值>实际读入的元素数

<适用>文件流

 3.使用示范

//头文件同上略//fwrite  freadtypedef struct stu{	int n;	float score;	char name[10];}stu;int main(){	stu s = {10,100.0,"张三"};	FILE*pr = fopen("test.txt","rb");	struct stu s1 = { 0 };	if (pr == NULL)	{		printf("%s",strerror(errno));		return 0;	}	//fwrite(&s,sizeof(stu),1,pw);	fread(&s1,sizeof(stu),1,pr);	fclose(pr);	pr = NULL;	return 0;}

⑥fseek与ftell与rewind

1.fseek

<功能>将文件指针移到指定的位置

<参数>offset-偏移量        origin-初始化文件指针位置

            origin有三种选择:SEEK_CUR  从当前位置开始

                                           SEEK_END  从文件结尾开始

                                           SEEK_SET   从文件开头开始

<返回值>成功返回0,失败返回非0值

<注意>对文件指针的修改不可以通过p++的方式实先

 使用演示(现已知记事本储存数据为“abcdef”)

//fseekint main(){	FILE*pr = fopen("test.txt","r");	int a = 0;	if (pr == NULL)	{		printf("%s",strerror(errno));		return 0;	}	//定位文件指针	fseek(pr, -1, SEEK_END);//指向最后一个的后一个	a=fgetc(pr);    b=ftell(pr);//返回当前指针位置	printf("%c",a);    printf("%d",b);	fclose(pr);	pr = NULL;	return 0;}

(若初始化文件指针为SEEK_SET,偏移1则得到b)

2.ftell

<功能>返回当前文件指针的偏移量 

3.rewind

<功能>使文件指针回到文件的开始

使用演示

int main(){	int n;	FILE * pFile;	char buffer[27];	pFile = fopen("test.txt", "w+");	for (n = "A"; n <= "Z"; n++)		fputc(n, pFile);	rewind(pFile);	fread(buffer, 1, 26, pFile);	fclose(pFile);	buffer[26] = "/0";	puts(buffer);	return 0;}

⑦ferror与feof

1.ferror

<功能>检查流是否发生了错误

<返回值>若发生错误则返回0,否则返回非0值

2.feof

  

<功能>当文件读取结束的时候,判断是读取失败结束,还是遇到文件尾结束

<返回值>若不是文件末尾则返回0,是文件末尾则返回非0值

<注意>不能用feof函数的返回值直接用来判断文件的是否结束

1. 文本文件读取是否结束,判断返回值是否为EOF (fgetc),或者NULL(fgets)
例如:
fgetc判断是否为EOF.
fgets判断返回值是否为NULL.
2. 二进制文件的读取结束判断,判断返回值是否小于实际要读的个数。
例如:
fread判断返回值是否小于实际要读的个数

使用演示(对于文本文件)

int main(void){	int c; // 注意:int,非char,要求处理EOF,EOF本质上是-1	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))		puts("I/O error when reading");	else if (feof(fp))		puts("End of file reached successfully");	fclose(fp);}

 使用演示(对于二进制文件)

enum { SIZE = 5 };int main(void){	double a[SIZE] = { 1.0, 2.0, 3.0, 4.0, 5.0 };	double b = 0.0;	size_t ret_code = 0;	FILE *fp = fopen("test.bin", "wb"); // 必须用二进制模式	fwrite(a, sizeof(*a), SIZE, fp); // 写 double 的数组     sizeof(*)表示这种类型大小	fclose(fp);	fp = fopen("test.bin", "rb");	// 读 double 的数组	while ((ret_code = fread(&b, sizeof(double), 1, fp)) >= 1)	{		printf("%lf/n", b);	}	if (feof(fp))		printf("Error reading test.bin: unexpected end of file/n");	else if (ferror(fp)) {		perror("Error reading test.bin");	}	fclose(fp);	fp = NULL;}

⑧补充函数 sscanf sprintf  

1.sprintf

<功能>将特定格式的数据写入字符串

<参数>buffer-输出的储存位置 

<返回值>写入字符串的数据大小(单位字节)

2.sscanf

<功能>从字符串中读取特定格式的字符串

3.使用演示

//sprintf  sscanftypedef struct stu{	int n;	float score;	char name[10];}stu;int main(){	stu s = {10,3.14,"张三"};	char buf1[1024] = {0};	stu s1 = {0};	sprintf(buf1, "%d %f %s",s.n,s.score,s.name);//不要再加上n=...,score=...	sscanf(buf1,"%d %f %s",&(s1.n),&(s1.score),&(s1.name));	printf("%d/n",s1.n);	printf("%s/n",s1.name);	return 0 ;}

⑨补充函数perror  strerror

 <比较>perror和strerror相比不需要引用errno变量,也不需要使用printf函数,操作更加便捷。同时自行输入的字符串起到标识的作用,不会混淆。

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/121971.html

相关文章

  • 13 万字 C 语言从入门到精通保姆教程2021 年版 (建议收藏)

    摘要:友情提示先关注收藏,再查看,万字保姆级语言从入门到精通教程。及大牛出天地开始有随之乃有万种语年英国剑桥大学推出了语言。 友情提示:先关注收藏,再查看,13 万字保...

    zombieda 评论0 收藏0
  • 保姆教程】从零到精通Git,CodeChina实战

    摘要:因为是全中文的,对一些英语不好的人来说确实是福利。二下载安装下载官网下载地址进去之后,点击点击后就会自动下载了。 文章目录 推荐系列教程,推荐的一定是精选的!一....

    lyning 评论0 收藏0
  • 0基础C语言保姆教学——第五节 数组

    摘要:关注我,订阅专栏基础语言保姆教学,就可以持续读到我的文章啦本文为万字长文,满满干货。那么,上面的代码所运行的结果就是一维数组的使用使用即可以访问并可以修改,即可读可写。 大家好~~~我是开心学编程,学到无极限的@jxwd? 写在前面: 各位小伙伴还在为C语言的学习而苦恼嘛? 还在为...

    RobinQu 评论0 收藏0
  • 保姆教程HTML两万字笔记大总结【建议收藏】(上篇)

    摘要:标签不区分大小写,但推荐小写。标签可以嵌套,但不能交叉嵌套。标签也称为元素。比如行内标签亦可成行内元素。 ❤️HTML必备知识详解❤️ 第一部分:HTML框架简介...

    paulli3 评论0 收藏0
  • 使用frp配置内网(穿透[保姆教程])

    摘要:简介是一个开源简洁易用高性能的内网穿透和反向代理软件,支持等协议。是一个可用于内网穿透的高性能的反向代理应用,分为服务端和客户端,支持协议。是该条规则在服务端开放的端口号,自己填写并记录即可。 ...

    yeooo 评论0 收藏0

发表评论

0条评论

最新活动
阅读需要支付1元查看
<