目录
一、为什么用文件
最近我写了一个通讯录,如下图,第一次运行的时候,我添加了2个联系人的信息,再次运行的时候,数据全部丢失,又得添加。那有没有一种方法,可以让数据保存起来,下次需要的时候程序直接导入就可以,不用手动添加呢?当然!一共有两个选择,一个是用数据库存储,另一个是用文件存储。那接下来,我带大家一起来学习一下C语言的文件操作。
二、文件的打开和关闭
1.文件简介
上面提到了,文件可以永久的将数据保存到本地的硬盘上。在学习文件之前,还需要了解文件的一些知识。
首先,一个文件一定有一个它的标识,并且这个标识是唯一的,可以让程序准确地找到我们想要编辑的文件;这个标识由三部分组成:文件路径+文件名+文件后缀。
如上图:“C:\大学\code\AddressBook\Debug\"这个就是文件路径,表示这个文件在C:盘的目录下,大学这个文件夹里,点进去之后又有一个code文件夹,再点进去……
"AddressBook"就是文件名,".exe"是文件的后缀,文件后缀决定了文件默认以何种形式打开。
2.文件指针
了解了一些基础知识后,我们来学习一下文件指针这个概念。当我们打开一个文件后,编译器会自动创建一个结构体,这个结构体中存储了文件的相关信息,例如文件的名字,文件的位置等等,里面存的什么,怎么使用,不是我们关心的事,我们只用知道有这么一个结构体,它的类型是FILE,打开文件后,系统会给我们一个FILE类型的指针变量,我们只用知道可以通过这个变量来维护文件(从文件中读数据,将数据写到文件)就可以了。这个FILE类型的指针,称为文件指针。
3.文件的打开
打开文件需要用到一个函数 fopen。
FILE* fopen(const char* filename, const char* mode);
该函数会打开一个文件,被打开的文件标识是 filename,filename可以没有文件路径,这种情况下默认是当前路径,mode是打开文件的方式,可以是只读的形式打开,也可以是只写的形式打开,还可以是又读又写的形式打开。最终,fopen函数返回一个文件指针。
FILE* pf = fopen("AddressBook.txt", "rb");
上面这条语句执行的结果是,会在当前程序执行的路径下打开"AddressBook.txt"文件,以"rb"的形式打开,同时内存会开辟一块空间来存放该文件的信息,并返回一个FILE类型的指针指向这块空间,以供我们维护这个文件。
4.文件打开的方式
(该图片来源于:比特就业课)
下面讲一些需要注意的点
(1)如下图,现在要在默认目录下以读的形式打开一个文件,很显然,这个文件目前不存在。
这个时候,fopen会返回一个空指针
所以在使用fopen函数的时候,我们需要检测返回值是否为空;
(2)还和刚刚一样,这次我们以写的形式打开,目录下依然没有该文件
但是这次在执行完之后,系统自动创建了一个文件,并且打开文件成功
程序结束之后,文件仍任存在。
(3)在使用带 “w” 的形式打开文件时("w","w+","wb+"),原先的数据会被全部清空。
现在这个文件中存储了一些数据
但运行完之后,文件中的内容被清空了。
5.文件的关闭
当我们打开一个文件时,系统会分配一块内存并返回一个FILE型的指针让我们维护这个文件,因此,在使用完文件之后,我们理应关闭文件,将这块内存还给系统,就好比你从图书馆借了一本书,你看完之后不看了,又不还,其他人想看又看不了。所以我们把这块空间还给系统之后,系统又可以把这块空间给其他人使用。(关闭文件还有更多的特点,在此先不做过多说明)
关闭文件的函数是 fclose。
int fclose(FILE* stream);
如果文件被关闭,返回0,否则,返回EOF。
三、文件的读写
1. fgetc 与 fputc
int fgetc(FILE* stream);
返回stream中的内部文件指示器当前指向的字符,然后将内部文件指示器指向下一个字符。
说白了就是一个字符一个字符读取。示例如下:
如图所示,fgetc函数会一个一个读取文件中的字符,如果读到了末尾,就会返回EOF。
int fputc(int character, FILE* stream);
fputc与fgetc对应,这个函数会一个一个的往文件中写入字符。
2. fgets 与 fputs
char* fgets(char* str, int num, FILE* stream);
fgets会从stream中读取一些字符并把它们存放到str指向的C字符串中,直到 num-1 个字符串被读或者遇到了新的一行或者读到了EOF。
一个换行符使fgets函数停止读取,但是它会被认为是一个合法的字符,并且拷贝到str中。
一个空字符自动被附加到str的末尾。如下图所示:
fputs更加简单,就是将str中的字符串拷贝到stream指向的文件中,遇到'\0‘就停下来,但是'\0'并不会被拷入文件。
int fputs(const char* str, FILE* stream);
3. fscanf 与 fprintf
这两个函数其实就是格式化的读写。
int fscanf(FILE* stream, const char* format, ...);
int fprintf(FILE* stream, const char* format, ...);
它们与我们平常使用的scanf和printf并没有太大的区别,只是多了一个FILE型的指针,告诉程序要从哪里读,写到哪里。