一、学习文件操作的意义
C语言的文件操作其实很少用到,因为在后期工作中他们大多数都被封装好了,我们直接使用就行,但是对于一名修内功的程序员,了解更加底层的实现方式,还是很有价值的.
还记得之前实现的通讯录吗?
每次重新打开通讯录,里面的数据都是空的,即使上次有输入过数据,但是每次退出通讯录之后,数据都会被丢弃了.这就很不方便,如果我们想将之前通讯录的数据保留下来(即关闭程序后,下次打开,数据还在),数据如果保存在内存中,数据断电就会丢失,此时我们可以使用文件操作,将数据保存在硬盘中.这样就可以让数据持久化.
二、文件是什么?
2.1 文件分类
磁盘上的文件就是文件。(说了等于没说)😂😂😂
在程序设计中,我们所说的文件指按文件功能来分类,主要有两种:
1.程序文件:
源程序文件(后缀为.c)
目标文件(windows环境后缀为.obj)
可执行程序(windows环境后缀为.exe)等等.
2.数据文件
文件的内容不一定是程序,也可以是程序运行时读写的数据,向文件中写入数据,或者从数据文件中读取数据,这类文件被称为数据文件.
本篇文章主要讨论如何对文件进行读写操作(写:向文件写入数据,读:从文件中读取数据),所以重点是讲解数据文件.
2.2 文件名的组成
上面只谈到了后缀名,那文件名有哪些部分组成呢?
一个文件要有一个唯一的文件标识,一方面让电脑能够识别和查找,另一方面以便用户识别和引用。
文件名包含3部分:文件路径+文件名主干+文件后缀
例如: 文件名如下
E:\编程\代码库\c语言代码库\进阶\c-language---advanced\文件操作\test.c
文件路径:E:\编程\代码库\c语言代码库\进阶\c-language---advanced\文件操作
文件名主干:test
文件后缀名:.c
为了方便起见,文件标识常被称为文件名.
三、如何使用代码打开和关闭文件?
文件指针:
首先我们介绍一下文件指针,每个被使用的文件都在内存中开辟了一个相应的文件信息区,用来存放文件的相关信息(如文件的名字,文件状态及文件当前的位置等)。这些信息是保存在一个结构体变量中的。该结构体类型是由系统声明的,取名FILE,而文件指针是指向该结构体的指针.即指向某一文件的指针变量,
不同的C编译器的FILE类型包含的内容不完全相同,但是大同小异。不过这点我们并不关心,我们只需要会使用FILE就行.
如何使用FILE指针呢?
这就是我们下面要讲解的文件的打开和关闭内容.
我们在使用文件时,要先将这个文件打开,并且结束后将文件关闭.
//打开文件 FILE * fopen ( const char * filename, const char * mode ); //关闭文件 int fclose ( FILE * stream )
参数说明:
fopen:
参数 | 含义 |
filename | 要打开的文件的文件名 |
mode | 打开方式 |
该函数,如果打开文件失败,返回NULL指针
fclose:
参数 | 含义 |
stream | 指向要关闭的文件指针 |
打开方式详见如下表:
3.1 文件"打开方式"表
使用方式 | 含义 | 文件状态(不存在) |
“r”(只读) | 为了输入数据,打开一个已经存在的文本文件 | 出错 |
“w”(只写) | 为了输出数据,打开一个文本文件 | 建立一个新的文件 |
“a”(追加) | 向文本文件尾添加数据 | 建立一个新的文件 |
“rb”(只读) | 为了输入数据,打开一个二进制文件 | 出错 |
“wb”(只写) | 为了输出数据,打开一个二进制文件 | 建立一个新的文件 |
“ab”(追加) | 向一个二进制文件尾添加数据 | 出错 |
“r+”(读写) | 为了读和写,打开一个文本文件 | 出错 |
“w+”(读写) | 为了读和写,建议一个新的文件 | 建立一个新的文件 |
“a+”(读写) | 打开一个文件,在文件尾进行读写 | 建立一个新的文件 |
“rb+”(读写) | 为了读和写打开一个二进制文件 | 出错 |
“wb+”(读写) | 为了读和写,新建一个新的二进制文件 | 建立一个新的文件 |
“ab+”(读写) | 打开一个二进制文件,在文件尾进行读和写 | 建立一个新的文件 |
这张表只是介绍了用何种方式打开文件进行读写,那具体怎样读写呢?↓
3.2 "流"是什么意思?(很重要)
如果我们需要进行数据交换的对象是显示器,文件,网络,打印机等输出设备时,我们需要了解每一个对象的读写方式吗?这未免也要麻烦了,对操作人员的要求是不是也很高?
那我们就引入了流的概念,我们只需要通过流来进行输入输出操作就行了,对应的实现C语言帮我们搞定了.
一个C语言程序,打开后,默认会打开三个流(stream):
- stdin:标准输入流 --键盘
- stdout:标准输出流 --显示器
- stderr:标准错误流
要分清输入和输出的概念:
常见的键盘读取和显示器输出:↓
对文件的输入和输出:↓
总结:
对于fread和fwrite函数,它们两个只针对文件流负责
scanf和printf是标准的输入和输出流,他们也只针对键盘和显示器(屏幕)负责.
而其他函数,他们既可以从键盘读取数据,也可以从文件或者其他流读取数据.
向内存存数据是输入操作,找内存要数据就是输出.
上面的一个是键盘往内存输入数据,一个是文件往内存中存.
四、开启正式的读写文件操作
有了上面的基础知识的学习,我们现在可以开始写文件了.
#include <stdio.h> int main() { FILE* pFile; //打开文件 pFile = fopen("123.txt", "r"); //文件名:123 --这里是相对路径 //文件名后缀:.txt //打开方式:"r" --为了输入数据,打开一个已经存在的文本文件 if (pFile != NULL) { fputs("Hello World !", pFile); } else { printf("打开失败"); return 1;//返回非0 } //关闭文件 fclose(pFile); return 0; }
运行结果:
打开失败
原因:
在相对路径下,没有"123.txt"文件.
补充知识:
1、相对路径:就是相对于自己的目标文件的位置。从当前文件所在文件夹开始(指以当前文件所处目录而言文件的位置)————以引用文件之间网页所在位置为参考基础,而建立出的目录路径。故称之为相对。
例如:123.txt(它的当前目录就是test.c所在的文件夹)
2、绝对路径:是指文件在硬盘上真正存在的路径。从根目录开始(指对站点的根目录而言某文件的位置)
例如:E:\编程\代码库\c语言代码库\进阶\c-language---advanced\文件操作\123.xt
我们新建一个"123.txt"文件,
#include <stdio.h> int main() { FILE* pFile; //打开文件 pFile = fopen("123.txt", "w");//这里改成"写" //文件名:123 --这里是相对路径 //文件名后缀:.txt //打开方式:"w" --为了输出数据,打开一个已经存在的文本文件 if (pFile != NULL) { //打开成功写文件 fputs("Hello World !", pFile); } else { printf("打开失败"); return 1;//返回非0 } //关闭文件 fclose(pFile); return 0; }
运行结果:
找到123.txt文件,双击打开查看内容.