前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >【C语言】文件操作

【C语言】文件操作

作者头像
YoungMLet
发布2024-03-01 09:06:24
1020
发布2024-03-01 09:06:24
举报
文章被收录于专栏:C++/Linux

一、什么是文件

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

1. 程序文件

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

2. 数据文件

文件的内容不一定是程序,而是程序运行时读写的数据,比如程序运行需要从中读取数据的文件,或者输出内容的文件。

在以前各章所处理数据的输入输出都是以终端为对象的,即从终端的键盘输入数据,运行结果显示到显示器上。其实有时候我们会把信息输出到磁盘上,当需要的时候再从磁盘上把数据读取到内存中使用,这里处理的就是磁盘上文件。

二、文件的打开和关闭

1. 文件指针

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

每当打开一个文件的时候,系统会根据文件的情况自动创建一个FILE结构的变量,并填充其中的信息,一般都是通过一个FILE的指针来维护这个FILE结构的变量.

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

内存相当于我们的大脑,文件相当于一张纸,读(输入)就是从外界读取知识,写(输出)就是将大脑现有的知识写出来;

2. 文件的打开和关闭

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

打开文件使用fopen函数,关闭文件使用fclose函数;

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

其中,const char *filename是文件名,const char *mode 是打开方式;

3. 打开方式

打开方式如下:

代码语言:javascript
复制
		文件使用方式               含义                              如果指定文件不存在
		“r”(只读)       为了输入数据,打开一个已经存在的文本文件     出错
		“w”(只写)       为了输出数据,打开一个文本文件              建立一个新的文件
		“a”(追加)       向文本文件尾添加数据                       建立一个新的文件
		“rb”(只读)      为了输入数据,打开一个二进制文件            出错
		“wb”(只写)      为了输出数据,打开一个二进制文件            建立一个新的文件
		“ab”(追加)      向一个二进制文件尾添加数据                  出错
		“r+”(读写)      为了读和写,打开一个文本文件                出错
		“w+”(读写)      为了读和写,建议一个新的文件                建立一个新的文件
		“a+”(读写)      打开一个文件,在文件尾进行读写              建立一个新的文件
		“rb+”(读写)     为了读和写打开一个二进制文件                出错
		“wb+”(读写)     为了读和写,新建一个新的二进制文件          建立一个新的文件
		“ab+”(读写)     打开一个二进制文件,在文件尾进行读和写      建立一个新的文件

打开文件和关闭文件的使用:

代码语言:javascript
复制
			//打开文件
			int main()
			{
				//打开文件
				FILE* pf = fopen("test.txt", "w");
				//打开文件失败会返回NULL,所以要断言判断pf是否为空
				assert(pf);
				//写文件
				//.....
				//关闭文件
				fclose(pf);
				pf = NULL;
				return 0;
			}

三、 文件的顺序读写

代码语言:javascript
复制
		功能   				函数名 				适用于
		字符输入函数 		fgetc 				所有输入流
		字符输出函数 		fputc 				所有输出流
		文本行输入函数 		fgets 				所有输入流
		文本行输出函数 		fputs 				所有输出流
		格式化输入函数 		fscanf 				所有输入流
		格式化输出函数 		fprintf 			所有输出流
		二进制输入 			fread 				文件
		二进制输出 			fwrite 				文件

1. fputc - 写文件

代码语言:javascript
复制
		int main()
		{
			FILE* pf = fopen("test.txt", "w");
			assert(pf);
		
			//写文件
			//将26个字母写进文件
			for (int i = 0; i < 26; i++)
			{
				fputc('a' + i, pf);
			}
			
			fclose(pf);
			pf = NULL;
		
			return 0;
		}

2. fgetc - 读文件操作

代码语言:javascript
复制
		int main()
		{
			//打开
			FILE* pf = fopen("test.txt", "r");
			assert(pf);
		
			//读文件
			for (int i = 0; i < 26; i++)
			{
				char ch = fgetc(pf);
				printf("%c ", ch);
			}
			
			//关闭
			fclose(pf);
			pf = NULL;
			return 0;
		}

3. fputs - 写一行数据

代码语言:javascript
复制
		int main()
		{
			FILE* pf = fopen("test.txt", "w");
			char ch[] = "hello bit";
			fputs(ch, pf);
		
			fclose(pf);
			pf = NULL;
			return 0;
		}

4. fgets - 读一行数据

代码语言:javascript
复制
		int main()
		{
			FILE* pf = fopen("test.txt", "r");
			//把文件中读到的文件放在ch
			char ch[20];
			//读6个字符,包括\0,放到ch
			fgets(ch, 6, pf);
			printf("%s\n", ch);
		
			fclose(pf);
			pf = NULL;
			return 0;
		}

5. fprintf - 格式化输入函数

代码语言:javascript
复制
		struct S
		{
			int n;
			float a;
			char arr[20];
		};
		
		int main()
		{
			struct S s = { 10,3.14,"abcde" };
			FILE* pf = fopen("test.txt", "w");
			assert(pf);
		
			fprintf(pf, "%d %f %s\n", s.n, s.a, s.arr);
		
			fclose(pf);
			pf = NULL;
			return 0;
		}

6. fscanf - 格式化输出函数

代码语言:javascript
复制
		struct S
		{
			int n;
			float a;
			char arr[20];
		};
		
		int main()
		{
			struct S s = { 0 };
			FILE* pf = fopen("test.txt", "r");
			assert(pf);
		
			fscanf(pf, "%d %f %s", &(s.n),&(s.a),s.arr);
			printf("%d %f %s", s.n, s.a, s.arr);
		
			fclose(pf);
			pf = NULL;
			return 0;
		}

7. fread - 二进制的读文件

代码语言:javascript
复制
		struct S
		{
			char name[20];
			int age;
			float score;
		};
		
		int main()
		{
			struct S s = {0};
			FILE* pf = fopen("test.txt", "rb");
			assert(pf);
		
			//读文件
			fread(&s, sizeof(struct S), 1, pf);
			printf("%s %d %f\n", s.name, s.age, s.score);
		
			//关闭文件
			fclose(pf);
			pf = NULL;
		
			return 0;
		}

8. fwrite - 二进制的写文件

代码语言:javascript
复制
		int main()
		{
			struct S s = { "zhangsan", 20, 95.5f };
			FILE*pf = fopen("test.txt", "wb");
			assert(pf);
		
			//写文件
			fwrite(&s, sizeof(struct S), 1, pf);
		
			//关闭文件
			fclose(pf);
			pf = NULL;
		
			return 0;
		}

四、流的概念

当我们需要写数据到文件,屏幕,网络等等这种外部设备时,对于程序员来说要求太高了,所以抽象出一种 ‘流’ 的概念,程序员只需要把数据写到’ 流 '里面去,至于‘流’中的数据如何传到外部设备,我们不需要关注;

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

在C语言程序中,会默认打开3个流:

代码语言:javascript
复制
终端设备-屏幕: 标准输出流	    stdout
键盘:          标准输入流	    stdin
屏幕:          标准错误流  		stderr

代码演示:

代码语言:javascript
复制
		int main()
		{
			//从标准输入流中读取数据
			int ch = fgetc(stdin);
			printf("%c\n", ch);
		
			//标准输出流
			fputc('a',stdout);
		
			return 0;
		}

五、对比一组函数

scanf / fscanf / sscanf printf / fprintf / sprintf

代码语言:javascript
复制
		scanf		针对标准输入流(stdin)的格式化输入函数
		printf		针对标准输出流(stdout)的格式化输出函数
		
		fscanf		针对所有输入流(文件流,stdin)的格式化输入函数
		fprintf		针对所有输出流文件(文件流,stdout)的格式化输出函数
		
		sscanf		把字符串转换成格式化的数据
		sprintf		把格式化的数据转换成字符串

sscanf 和 sprintf

代码语言:javascript
复制
		struct S
		{
			int n;
			float f;
			char arr[20];
		};
		
		int main()
		{
			struct S s = { 200, 3.5f, "lisi" };
			//把一个结构体转换成字符串
			char arr[200] = { 0 };
			sprintf(arr, "%d %f %s\n", s.n, s.f, s.arr);
			printf("字符串的数据:%s\n", arr);
		
			//把一个字符串转换成对应的格式化数据
			struct S tmp = { 0 };
			sscanf(arr, "%d %f %s", &(tmp.n), &(tmp.f), tmp.arr);
			printf("格式化的数据:%d %f %s\n", tmp.n, tmp.f, tmp.arr);
		
			return 0;
		}

六、 文件的随机读写

(1)fseek

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

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

最后一个参数可以指定是:

在这里插入图片描述
在这里插入图片描述
代码语言:javascript
复制
		int main()
		{
			FILE* pf = fopen("test.txt", "r");
			assert(pf);
			//读文件
			int ch = fgetc(pf);
			printf("%c\n", ch);//a
			ch = fgetc(pf);
			printf("%c\n", ch);//b
			ch = fgetc(pf);
			printf("%c\n", ch);//c
			ch = fgetc(pf);
			printf("%c\n", ch);//d
		
			//fseek(pf, -3, SEEK_CUR);
			fseek(pf, 1, SEEK_SET);
			ch = fgetc(pf);
			printf("%c\n", ch);//希望读到的是b
		
			//关闭文件
			fclose(pf);
			pf = NULL;
			return 0;
		}

(2)ftell和rewind

代码语言:javascript
复制
		int main()
		{
			FILE* pf = fopen("test.txt", "r");
			assert(pf);
			
			//读文件
			int ch = fgetc(pf);
			printf("%c\n", ch);//a
			ch = fgetc(pf);
			printf("%c\n", ch);//b
			ch = fgetc(pf);
			printf("%c\n", ch);//c
			ch = fgetc(pf);
			printf("%c\n", ch);//d
		
			//让文件指针的位置回到文件的起始位置
			rewind(pf);
		
			//返回文件指针相对于起始位置的偏移量,即现在的偏移量相对于起始位置是多少
			printf("%d\n", ftell(pf));//0
		
			ch = fgetc(pf);
			printf("%c\n", ch);//a
		
			//关闭文件
			fclose(pf);
			pf = NULL;
			return 0;
		}

七、 文件读取结束的判定

feof - 文件读取结束的判定

在文件读取过程中,不能用feof函数的返回值直接用来判断文件的是否结束。而是应用于当文件读取结束的时候,判断是读取失败结束,还是遇到文件尾结束。

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

八、 文件缓冲区

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

代码语言:javascript
复制
		int main()
		{
			FILE* pf = fopen("test.txt", "w");
			
			fputs("abcdef", pf);//先将代码放在输出缓冲区
			printf("睡眠10秒-已经写数据了,打开test.txt文件,发现文件没有内容\n");
			Sleep(10000);
			
			printf("刷新缓冲区\n");
			fflush(pf);//刷新缓冲区时,才将输出缓冲区的数据写到文件(磁盘)
			
			//注:fflush 在高版本的VS上不能使用了
			printf("再睡眠10秒-此时,再次打开test.txt文件,文件有内容了\n");
			Sleep(10000);
			
			fclose(pf);
			//注:fclose在关闭文件的时候,也会刷新缓冲区
			pf = NULL;
			return 0;
		}
本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2024-01-03,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 一、什么是文件
    • 1. 程序文件
      • 2. 数据文件
      • 二、文件的打开和关闭
        • 1. 文件指针
          • 2. 文件的打开和关闭
            • 3. 打开方式
            • 三、 文件的顺序读写
              • 1. fputc - 写文件
                • 2. fgetc - 读文件操作
                  • 3. fputs - 写一行数据
                    • 4. fgets - 读一行数据
                      • 5. fprintf - 格式化输入函数
                        • 6. fscanf - 格式化输出函数
                          • 7. fread - 二进制的读文件
                            • 8. fwrite - 二进制的写文件
                            • 四、流的概念
                            • 五、对比一组函数
                              • sscanf 和 sprintf
                              • 六、 文件的随机读写
                                • (1)fseek
                                  • (2)ftell和rewind
                                  • 七、 文件读取结束的判定
                                  • 八、 文件缓冲区
                                  领券
                                  问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档